kill后表仍卡在waiting for table metadata lock,是因为mdl与事务生命周期绑定,kill仅发信号,事务未提交或回滚前锁不释放;需通过performance_schema.metadata_locks定位持有者,避免误杀。

为什么 KILL 之后表还是卡在 Waiting for table metadata lock
MySQL 的元数据锁(MDL)不是“谁加的锁谁负责释放”,而是和事务生命周期绑定的。执行 KILL 时,如果被杀会话正处于事务中且尚未提交或回滚,它的 MDL 会一直持有,直到事务真正结束——而 KILL 只是发信号,实际清理可能延迟几秒甚至更久,尤其在有大事务、磁盘 I/O 压力或正在刷 redo log 的时候。
-
KILL后立刻查SHOW PROCESSLIST看不到该线程,不代表锁已释放 - 如果被杀会话卡在
Rolling back状态,MDL 仍有效,其他 DDL 仍会被阻塞 -
KILL QUERY对 MDL 无效,必须用KILL(即KILL CONNECTION)
怎么快速定位哪个会话在持有元数据锁
优先查 performance_schema,比老式 INFORMATION_SCHEMA.PROCESSLIST 更准,能看清锁等待链:
执行以下语句找出正在等待 MDL 和持有 MDL 的会话:
SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_pid, r.trx_query waiting_query, b.trx_mysql_thread_id blocking_pid, b.trx_query blocking_query FROM performance_schema.threads t1 JOIN information_schema.INNODB_TRX r ON r.trx_mysql_thread_id = t1.PROCESSLIST_ID JOIN performance_schema.threads t2 ON t2.PROCESSLIST_ID = b.trx_mysql_thread_id JOIN information_schema.INNODB_TRX b ON b.trx_id = r.trx_wait_started WHERE r.trx_wait_started IS NOT NULL;
更直接的方式(MySQL 5.7+):
SELECT * FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'PENDING' OR LOCK_DURATION = 'TRANSACTION';
-
LOCK_STATUS = 'PENDING'表示正在等锁 -
LOCK_DURATION = 'TRANSACTION'表示该锁由活跃事务持有,事务不结束锁不释放 - 注意:需提前开启
performance_schema并启用metadata_locks消费者(UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'global_instrumentation';)
kill 之前必须确认的三件事
盲目 KILL 可能导致主从延迟突增、binlog 不一致或应用报错重试风暴:
- 查清
blocking_pid对应的应用模块、是否在跑定时任务或迁移脚本,避免误杀关键业务连接 - 确认该会话的事务是否可安全中断:
SELECT trx_state, trx_operation_state, trx_isolation_level FROM information_schema.INNODB_TRX WHERE trx_mysql_thread_id = ?;,若trx_state = 'RUNNING'且无写操作,风险较低;若已是'ROLLING BACK',KILL反而延长锁持有时间 - 检查
max_execution_time或wait_timeout是否过长,防止同类问题反复发生
kill 后锁没立刻释放?别硬等,试试强制刷新
某些场景下(如长事务 + 大量 undo 日志),即使 KILL 成功,MDL 释放也可能滞后。此时可尝试:
- 执行
FLUSH TABLES WITH READ LOCK;再UNLOCK TABLES;—— 这会强制刷新所有表的 MDL 缓存(注意:该操作会阻塞所有写入,慎用) - 若是 MySQL 8.0.13+,可尝试
ALTER TABLE ... FORCE触发隐式锁重置(仅对某些 DDL 场景有效) - 更稳妥的做法:等
INFORMATION_SCHEMA.INNODB_TRX中对应trx_id消失后再操作,不要依赖SHOW PROCESSLIST的线程消失
MDL 锁的“不可见性”是最容易被低估的点——它不记录在 INNODB_LOCKS,也不出现在 SHOW ENGINE INNODB STATUS 的传统锁信息里,全靠 performance_schema.metadata_locks 揭露。一旦习惯只看 PROCESSLIST,就容易反复踩坑。











