必须先查performance_schema.metadata_locks再关联threads和events_statements_current才能定位持锁者;show processlist因持锁线程常处sleep状态且state为空而无法识别,而mdl锁不经过innodb行锁路径,故data_locks与data_lock_waits对其无感。

必须先查 performance_schema.metadata_locks,再关联 threads 和 events_statements_current —— 单看一张表根本定位不到谁在 hold MDL 锁。
为什么 SHOW PROCESSLIST 只显示 Waiting for table metadata lock 却找不到持锁者
MDL 锁不走 InnoDB 行锁路径,data_locks 和 data_lock_waits 对它完全无感。持锁线程可能早已执行完 SQL、进入 sleep 状态,SHOW PROCESSLIST 里只显示 Command: Sleep,State 字段为空,但锁仍在 —— 因为 LOCK_DURATION = 'TRANSACTION' 的 MDL 锁会一直挂到事务提交或回滚。
-
metadata_locks表里LOCK_DURATION是关键字段:值为TRANSACTION的锁最危险,哪怕只执行了一条SELECT后没提交,就卡住所有 DDL - 持锁者可能不在活跃语句中:
events_statements_current.SQL_TEXT为NULL很常见,此时必须查INFORMATION_SCHEMA.INNODB_TRX.TRX_QUERY或TRX_STARTED时间戳人工比对 -
PROCESSLIST_ID不等于THREAD_ID,必须通过threads表做中间映射,否则KILL会杀错连接
怎么从 metadata_locks 找出真正持锁的会话
核心是三表连查:先筛出未释放的 MDL 锁,再绑定线程信息,最后捞出上下文。别跳步,漏一环就断链。
- 第一步:确认锁存在且未释放
SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'GRANTED' AND LOCK_DURATION = 'TRANSACTION'; - 第二步:关联持锁线程
SELECT m.OBJECT_SCHEMA, m.OBJECT_NAME, m.LOCK_TYPE, t.PROCESSLIST_ID, t.PROCESSLIST_INFO FROM performance_schema.metadata_locks m JOIN performance_schema.threads t ON m.OWNER_THREAD_ID = t.THREAD_ID WHERE m.LOCK_STATUS = 'GRANTED' AND t.TYPE = 'FOREGROUND'; - 第三步:查该线程最近执行的语句(如果有的话)
SELECT es.SQL_TEXT FROM performance_schema.events_statements_current es WHERE es.THREAD_ID = ?;(? 替换为上一步得到的THREAD_ID) - 若
SQL_TEXT为空,立刻 fallback 到:SELECT TRX_ID, TRX_STARTED, TRX_QUERY FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = ?;
data_lock_waits 查不到 MDL 等待?那是你找错了表
data_lock_waits 只管 InnoDB 层的行锁/页锁等待,对 MDL 完全不记录。想看 MDL 等待链,得用 metadata_locks + INNODB_TRX 拼接,而不是硬套 InnoDB 锁那一套逻辑。
- 常见错误:执行
SELECT * FROM performance_schema.data_lock_waits;返回空,就以为“没 MDL 锁争用”——这结论完全无效 - 正确做法:直接查
metadata_locks中LOCK_STATUS = 'PENDING'的条目,它对应正在等待 MDL 的会话;LOCK_STATUS = 'GRANTED'的才是持锁者 - 注意
OWNER_THREAD_ID是内部 ID,不是PROCESSLIST_ID,别拿它直接去KILL
容易被忽略的初始化前提
所有 metadata_locks 相关查询都依赖两个硬性开关,缺一不可:
-
performance_schema必须为ON:SELECT @@performance_schema;返回1 -
metadata_locksconsumers 必须启用:UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'global_instrumentation';(MySQL 8.0 默认开,但部分部署会手动关) - 不需要额外开启 instruments,
wait/lock/metadata/sql/mdl在 8.0 中默认启用,不用动setup_instruments
锁信息不是实时秒级刷新,有毫秒级延迟;刚加锁或刚释放时查不到是正常现象,别因此误判系统状态。











