真正要kill的是持有shared_read或shared_write锁的sleep连接,而非显示“waiting for table metadata lock”的线程;它通常是begin后未提交的悬挂事务,需通过performance_schema.metadata_locks定位granted锁对应的processlist_id,并用innodb_trx确认trx_state='running'。

DDL卡在Waiting for table metadata lock时,该杀谁?
真正要KILL的不是那个显示Waiting for table metadata lock的线程,而是背后持有SHARED_READ或SHARED_WRITE锁的连接。它往往看起来“什么都没干”——Command = 'Sleep'、State为空、Time却几百秒,实则是一个BEGIN后没COMMIT/ROLLBACK的悬挂事务。
- 先查
performance_schema.metadata_locks,确认LOCK_STATUS = 'GRANTED'且LOCK_TYPE为SHARED_READ或SHARED_WRITE的行 - 提取对应
PROCESSLIST_ID,再查information_schema.INNODB_TRX验证trx_state = 'RUNNING'且trx_started时间异常早 - 优先执行
KILL QUERY <process_id></process_id>(终止当前语句),再执行KILL <process_id></process_id>(断开连接);直接KILL可能触发长回滚
为什么SHOW PROCESSLIST找不到持锁者?
SHOW PROCESSLIST不显示MDL持有关系,因为元数据锁由MySQL服务层管理,和InnoDB事务锁分离。一个Sleep连接只要事务未结束,就一直持有MDL锁——哪怕它只执行过一条SELECT。
- REPEATABLE READ隔离级别下,事务内首次
SELECT会隐式加SHARED_READMDL锁,直到COMMIT或ROLLBACK -
mysqldump --single-transaction也会对所有dump表加SHARED_READ锁,dump未完成锁不释放 - 频繁查询
INFORMATION_SCHEMA.TABLES等系统表,也可能在高并发下成为隐形阻塞源
performance_schema.metadata_locks查不到数据怎么办?
默认可能未启用采集器,metadata_locks表会始终为空。必须手动开启对应instrument,否则所有定位操作都无效。
- 确认
performance_schema已开启:SELECT @@performance_schema;返回1 - 检查采集器状态:
SELECT * FROM performance_schema.setup_instruments WHERE NAME = 'wait/lock/metadata/sql/mdl'; - 若
ENABLED或TIMED为'NO',执行:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl'; - MySQL 5.7需额外确保
setup_actors启用:执行UPDATE performance_schema.setup_actors SET ENABLED = 'YES' WHERE HOST = '%';
有没有更快捷的定位方式?
MySQL 5.7+提供了sys.schema_table_lock_waits视图,能直接生成KILL命令,但依赖performance_schema.metadata_locks已启用,且只对明确的DDL等待有效。
- 查出阻塞DDL的连接:
SELECT sql_kill_blocking_connection FROM sys.schema_table_lock_waits WHERE blocking_lock_type 'SHARED_UPGRADABLE' AND waiting_query LIKE 'alter%'; - 注意:
SHARED_UPGRADABLE是可升级锁,不影响DDL,真正要杀的是SHARED_READ持有者 - 该视图在MySQL 8.0中更稳定;5.7中若
metadata_locks未启用,结果为空或不准
最易被忽略的一点:持锁事务可能来自应用连接池中的空闲连接,而非正在执行SQL的活跃线程——盯住Time字段比盯住Info更可靠。











