确认mdl锁阻塞需先查show processlist或information_schema.processlist,若state为“waiting for table metadata lock”,即基本确定;真正持锁者常是未提交事务、长查询或显式表锁,而非被堵的ddl本身,须结合performance_schema.metadata_locks定位持锁会话后再谨慎kill。

怎么确认是MDL锁导致的阻塞?
直接看 SHOW PROCESSLIST 或查 information_schema.PROCESSLIST,重点盯 STATE 字段:如果状态是 Waiting for table metadata lock,基本就是MDL锁卡住了。别只盯着DDL语句(比如 ALTER TABLE),它可能是被堵在后面;真正“持锁不放”的,往往是前面那个没结束的普通查询或事务——比如一个长 SLEEP()、未提交的 BEGIN、或大结果集的 SELECT。
为什么不能直接 KILL 阻塞者?
因为“阻塞者”未必是坏人——它可能只是个正常执行中的读操作,持有MDL读锁合情合理。真正该处理的是“持锁时间过长”的会话,比如:
- 运行超5分钟的
SELECT(尤其带SLEEP或大JOIN) - 处于
Transaction状态但没COMMIT或ROLLBACK的连接 -
INFO字段显示BEGIN后再无动作
盲目 KILL 这类会话,会导致事务回滚卡住(STATE 变成 Rolling back),反而延长阻塞时间。
怎么精准定位并终止源头会话?
分两步走:
1. 找出真正持锁的会话(不是那个卡住的 ALTER,而是它前面那个):
SELECT p.ID, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.STATE, p.INFO FROM information_schema.PROCESSLIST p JOIN performance_schema.threads t ON p.ID = t.PROCESSLIST_ID WHERE t.TYPE = 'FOREGROUND' AND p.TIME > 60 AND p.COMMAND != 'Sleep';
2. 结合 performance_schema.metadata_locks 查谁在等谁(MySQL 5.7+):
SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_STATUS, OWNER_THREAD_ID, OWNER_EVENT_ID FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'PENDING';
拿到 OWNER_THREAD_ID 后,反查 PROCESSLIST 中对应 ID,再决定是否 KILL CONNECTION。
云数据库上怎么办?
阿里云RDS、腾讯云CDB等默认屏蔽 information_schema.PROCESSLIST 全量视图,也禁用 KILL。这时候必须用控制台:
- 进“实时会话”页,按
State筛选Waiting for table metadata lock - 点开详情,看“阻塞来源”列(部分厂商已支持自动标注)
- 用控制台“终止会话”按钮,底层调用的是平台封装的安全终止逻辑,不会引发回滚风暴
别试图绕过权限去连内核态视图——多数云厂商已关闭 performance_schema 相关表的访问,硬查只会返回空或权限错误。











