SELECT被阻塞根本原因是MDL锁冲突:它需获取表的MDL共享锁,而DDL操作(如ALTER TABLE)正持有MDL排他锁,导致等待“Waiting for table metadata lock”;Navicat后台自动查询也会隐式持锁加剧阻塞。
select 查询被阻塞,根本原因不是“读被锁”,而是它背后触发了元数据锁(mdl)或与正在执行的 ddl 操作发生了冲突。mysql 的 select 本身不加行锁(在 rr 隔离级别下也不加间隙锁),但只要涉及表结构访问——比如查询 information_schema、执行 show create table、甚至 navicat 自动刷新表结构时——就会尝试获取 mdl 共享锁。而此时若另一会话正持有该表的 mdl 排他锁(如 alter table、drop index),你的 select 就会卡在 waiting for table metadata lock。
如何快速定位谁在持锁?
别依赖 Navicat 界面右上角的“刷新”按钮——它会默默触发元数据查询,反而加重阻塞。直接打开命令行界面(右键数据库 → “命令列界面”),执行:
SHOW PROCESSLIST;
重点关注 State 列含以下内容的行:
-
Waiting for table metadata lock:你自己的查询已卡住 -
altering table、copy to tmp table、rename result table:DDL 正在执行中,持着排他 MDL -
Locked或长时间updating(>10s)且Info显示大事务语句:可能阻塞了后续 MDL 获取
注意:User 为 navicat 或空值、Host 是本地 IP(如 127.0.0.1)的连接,大概率是 Navicat 自身发起的未提交操作或后台自动刷新任务。
为什么 kill DDL 还没用?
DDL 被 KILL 后,MySQL 需回滚内部状态(如清理临时文件、释放 buffer pool 页面),这个过程仍会短暂持有 MDL。更关键的是:等待队列里可能已有多个会话排队,只杀 DDL 发起者,其余等待者仍在原地挂起。
必须同步清理整条链:
- 先
KILL所有State = 'Waiting for table metadata lock'的会话(包括你自己的查询窗口) - 再
KILL正在执行 DDL 的会话(State含altering等) - 如果仍有残留,检查是否有未提交的长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW()) - TIME_TO_SEC(TRX_STARTED) > 60;
Navicat 自带工具怎么用才不翻车?
Navicat Premium 16+ 的「服务器监控 → 死锁进程」标签页能识别部分 MDL 等待,但它默认不显示 SHOW PROCESSLIST 中的全部细节。使用时务必:
- 勾选「Command = Query」且「Time > 30」的行,再按
State手动过滤含metadata lock的 - 绝对不要勾选
Command = Sleep的连接——那是正常空闲连接,杀掉会导致其他应用断连 - 结束进程后,立刻关闭并重开你的查询窗口,避免 Navicat 复用旧连接句柄继续卡死
真正防不住的坑:Navicat 自动后台行为
你没执行任何语句,表却突然查不动?很可能是 Navicat 在后台偷偷干活:
- 「对象浏览器」展开某张表时,自动执行
SHOW CREATE TABLE+SHOW INDEXES - 「设计表」界面打开瞬间,就申请了 MDL 共享锁,若此时有人正
ALTER,你就被拖下水 - 模型同步(Model Sync)全程重度依赖
information_schema,一次失败可能让整个连接卡在 MDL 等待中
这些操作不会出现在你手写的 SQL 历史里,也很难被 SHOW PROCESSLIST 明确标注来源。最稳的应对方式:遇到阻塞,先关掉所有 Navicat 表设计/模型/同步类窗口,再查进程、再清理。


















