MDL锁绑定事务生命周期,必须提交/回滚事务或KILL连接才能释放;KILL QUERY仅中断语句不结束事务,故无效;连接池复用、应用未关闭连接或异常退出均会导致锁长期持有,唯一有效解法是定位并KILL持锁线程或促使其事务终结。

MDL 锁不能靠“手动释放”,它绑定在事务生命周期上,必须终止持有锁的连接或提交/回滚事务才能解除。
为什么 KILL QUERY 不起作用
执行 KILL QUERY pid 只中断当前语句,不结束事务——而 MDL 锁是在事务开始时获取、事务结束时才释放的。只要事务还处于 TRX_STATE = 'RUNNING' 或 'LOCK WAIT' 状态,哪怕没在执行 SQL,锁就一直挂着。
-
KILL QUERY后查information_schema.INNODB_TRX,TRX_STARTED时间没变,说明事务还在 -
performance_schema.metadata_locks里仍能看到LOCK_DURATION = 'TRANSACTION'的记录 - 常见于 autocommit=0 下只执行了
SELECT ... FOR UPDATE就卡住,没COMMIT也没ROLLBACK
为什么重启 MySQL 连接也不一定有效
重启客户端连接(比如重连 MySQL CLI)只断开当前会话,但如果应用层用了连接池(如 HikariCP、Druid),旧连接可能被复用或未真正关闭;更关键的是,如果阻塞者是服务端长期运行的事务(比如报表导出任务),它根本不在你的客户端进程里。
- 应用未正确 close() connection → 连接在池中保持 idle,事务仍活跃
- Java 应用里 try-with-resources 漏写或 catch 后没 rollback → 事务悬空
- MySQL 客户端异常退出但服务端未及时清理(尤其低版本或 network timeout 设置过长)
真正有效的操作只有两个:KILL 或 COMMIT/ROLLBACK
必须定位到持有锁的线程 ID,再决定是强制终止还是引导业务侧收口。别跳过确认步骤直接杀。
- 先查
sys.schema_table_lock_waits(MySQL 8.0)或手连INNODB_TRX+performance_schema.threads(5.7) - 重点看
BLOCKING_PID和对应线程的PROCESSLIST_INFO,确认是不是UPDATE卡在应用层、还是SELECT ... FOR UPDATE忘记提交 -
KILL pid是最终手段;若阻塞者是核心业务长事务(如批量导入),应先通知负责人,而非直接 kill - 如果能登录应用服务器,优先让应用执行
rollback或commit,比 kill 更安全
MDL 锁的顽固性不在于它多复杂,而在于它和事务边界强绑定——你看到的“卡住”,往往是某个地方忘了收尾。查锁容易,找那个没 commit 的人最难。











