看到Waiting for table metadata lock,说明是MDL锁阻塞,需查sys.schema_table_lock_waits定位blocking_pid持锁者,而非kill waiting_pid;若返回为空,先确认performance_schema启用及mdl采集器开启,blocking_pid为NULL时可能为隐式事务悬挂持锁。

看到 Waiting for table metadata lock,不用猜——就是有线程正拿着元数据锁(MDL)不放,你的 DDL 或查询被卡住了。真正要杀的不是那个显示“Waiting”的线程,而是背后那个“安静”持锁的事务。
查 sys.schema_table_lock_waits 快速定位谁在堵谁
这是 MySQL 5.7+ 最直接的诊断入口,它把阻塞关系一次性列清楚:blocking_pid 是持锁者,waiting_pid 是受害者,sql_text 甚至能告诉你持锁者最后执行了什么。
- 执行
SELECT * FROM sys.schema_table_lock_waits\G,优先看blocking_pid非 NULL 的行 - 如果返回为空,先确认
performance_schema已启用:SELECT @@performance_schema;应为 1 - 再检查采集器是否开启:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl'; -
blocking_pid为 NULL 不代表没锁,很可能是隐式事务(如BEGIN后只跑了一条SELECT就断开)在持锁
联合 INNODB_TRX 和 PROCESSLIST 找“Sleep 却 RUNNING”的悬挂事务
大量阻塞源不是正在跑 SQL 的线程,而是那种 COMMAND = 'Sleep'、STATE 为空、但 TIME > 300 且 INFO 为空的连接——它大概率 BEGIN 了却没 COMMIT,从启动就一直占着 MDL_SHARED_READ 锁。
- 必须用 JOIN 查,单查
INNODB_TRX会漏掉已断连但事务未清理的连接:SELECT t.trx_id, t.trx_started, t.trx_state, p.ID, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.STATE, p.INFO FROM information_schema.INNODB_TRX t JOIN information_schema.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE p.COMMAND = 'Sleep' AND t.trx_state = 'RUNNING' ORDER BY t.trx_started; - 重点看
trx_started时间:越早越可疑;trx_isolation_level = 'REPEATABLE READ'时,哪怕只执行过一条SELECT,事务一启就持 MDL 锁 -
INFO为空 +TIME > 600→ 90% 是应用异常中断或忘记COMMIT
用 performance_schema.metadata_locks 确认持锁细节
SHOW PROCESSLIST 不显示谁在 hold MDL 锁,因为它是服务层锁,得靠 performance_schema.metadata_locks 看真实状态。
- 先确认采集器已开:
SELECT * FROM performance_schema.setup_instruments WHERE NAME = 'wait/lock/metadata/sql/mdl';,确保ENABLED和TIMED都是 YES - 查具体表的锁情况(替换
your_db和your_table):SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_STATUS, PROCESSLIST_ID, PROCESSLIST_USER, PROCESSLIST_HOST FROM performance_schema.metadata_locks m JOIN performance_schema.threads t ON m.OWNER_THREAD_ID = t.THREAD_ID WHERE OBJECT_SCHEMA = 'your_db' AND OBJECT_NAME = 'your_table'; - 重点关注
LOCK_STATUS = 'GRANTED'且LOCK_TYPE为SHARED_READ或SHARED_WRITE的行——这些才是真正在持锁的连接
KILL 前务必用 SHOW ENGINE INNODB STATUS\G 确认空转
别一看到线程 ID 就 KILL。有些线程虽然 STATE 是 Sleep,但可能刚执行完大事务正准备提交,或者正在写 binlog——误杀会导致主从不一致或数据丢失。
- 从上一步查出的
trx_id,在SHOW ENGINE INNODB STATUS\G输出里搜索对应事务段 - 看
mysql tables in use和locked tables是否都为 0:是 → 基本没在干活,可KILL - 若
trx_query为空、trx_state = 'RUNNING'、且trx_started超过 10 分钟,基本坐实是悬挂事务
最常被忽略的一点:MDL 锁和引擎类型无关,MyISAM 表也会被阻塞;而 sys.innodb_lock_waits 根本查不到 MDL 问题,因为它只管行锁。


















