必须查performance_schema.metadata_locks才能准确定位持锁会话,它可显示表名、锁类型、持有者processlist_id及lock_duration;仅靠show processlist易误杀等待线程而无法释放锁。

查 performance_schema.metadata_locks 才能看到谁真正在持锁
SHOW PROCESSLIST 只显示线程状态,不显示锁归属。很多 DBA 看到一堆 Waiting for table metadata lock 就去 KILL 这些等待线程,结果锁还在——因为真正占着锁的是另一个已进入 Sleep 或 Query 状态的连接。
必须查 performance_schema.metadata_locks,它能告诉你:哪张表、哪种锁类型(MDL_SHARED_READ 还是 MDL_EXCLUSIVE)、由哪个会话持有(PROCESSLIST_ID)、锁持续时间(LOCK_DURATION)。
-
LOCK_DURATION = 'TRANSACTION'的行最危险:事务没提交,锁就一直挂着,哪怕TRX_QUERY是NULL - 需提前确认采集器已启用:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl'; - 还要打开消费者:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE 'global_instrumentation';
用 threads 表把 LOCK_OWNER 映射到真实会话 ID
metadata_locks.OWNER_THREAD_ID 是内部线程 ID,不能直接 KILL;必须关联 performance_schema.threads 表,拿到对应的 PROCESSLIST_ID——这才是 KILL 命令要传的数字。
典型查询语句:
SELECT m.OBJECT_SCHEMA, m.OBJECT_NAME, m.LOCK_TYPE, m.LOCK_DURATION, t.PROCESSLIST_ID, t.PROCESSLIST_USER, t.PROCESSLIST_HOST FROM performance_schema.metadata_locks m JOIN performance_schema.threads t ON m.OWNER_THREAD_ID = t.THREAD_ID WHERE m.OBJECT_SCHEMA = 'your_db' AND m.OBJECT_NAME = 'your_table' AND m.LOCK_STATUS = 'GRANTED' AND t.PROCESSLIST_ID IS NOT NULL;
重点筛出 PROCESSLIST_TIME > 60 且 PROCESSLIST_COMMAND = 'Sleep' 的行——这种空闲长连接最容易被忽略,但它持有的 TRANSACTION 级 MDL 锁正卡着你的 ALTER TABLE。
KILL CONNECTION 而不是 KILL QUERY
对持锁者执行 KILL QUERY 没用:它只中断当前语句,事务仍活跃,LOCK_DURATION = 'TRANSACTION' 的 MDL 锁不会释放。
必须用 KILL CONNECTION <code>id(或简写为 KILL <code>id),强制断连并回滚事务。但要注意:
- 如果该事务已修改大量数据,回滚本身可能持续数分钟,期间仍持有
MDL_EXCLUSIVE锁,反而延长阻塞 - 若持锁者只是个空闲
Sleep连接(比如应用层autocommit=0后断开未清理),KILL CONNECTION立即生效,无回滚开销 - 永远别对
User = 'system user'或Command = 'Connect'(复制线程)执行 KILL
别信 INNODB_TRX 里没事务就安全
INFORMATION_SCHEMA.INNODB_TRX 查不到事务,不代表没 MDL 锁。常见漏网情况:
- 显式
BEGIN后只执行了SELECT ... FOR UPDATE,没后续 DML,TRX_QUERY为空,但TRX_STATE = 'RUNNING'且TRX_STARTED很早 - 应用层设了
autocommit=0,执行完一条SELECT就断开,连接还活着,TRX_QUERY为空,TRX_STATE却是'ACTIVE' - 存储过程里隐式开启事务,外部查不到上下文
真正可靠的方式,是坚持从 metadata_locks + threads 联查入手,不依赖事务表字段是否“有内容”。











