mysql升级后mdl锁阻塞主因是未提交事务在8.0+中更暴露:sleep状态但trx_state='running',持有mdl锁不释放;需查innodb_trx中trx_query为空、trx_started早、trx_state='running'的记录定位。

MySQL升级后(尤其是5.7→8.0或更高),MDL锁机制更严格、默认行为更保守,导致原本“勉强能过”的DDL操作突然卡在Waiting for table metadata lock——这不是bug,而是锁校验逻辑变严了。关键不是绕开它,而是让长事务和连接池行为适配新规则。
如何一眼确认是升级后MDL变严引发的阻塞
升级后首次出现DDL卡住,且SHOW PROCESSLIST里大量线程状态为Waiting for table metadata lock,但阻塞源头不是显式LOCK TABLES或FLUSH TABLES WITH READ LOCK这类老式操作,而是普通SELECT或UPDATE语句后没提交的事务——这正是8.0+对未提交事务持有MDL锁更敏感的表现。
- 检查
performance_schema.metadata_locks是否已启用:执行SELECT * FROM performance_schema.setup_instruments WHERE NAME = 'wait/lock/metadata/sql/mdl',若ENABLED为NO,说明MDL监控被关闭,排查会失焦 - 对比升级前后
information_schema.INNODB_TRX里TRX_STARTED早于当前时间5分钟以上的记录数量——升级后这类“挂着的事务”更容易暴露成阻塞源 - 注意
sys.schema_table_lock_waits视图在8.0中默认可用,但在5.7需手动开启instrument;升级后若该视图查不到数据,大概率是遗漏了这个配置
为什么KILL QUERY经常无效,必须KILL CONNECTION
一个处于Sleep状态但TRX_STATE = 'RUNNING'的连接,其事务仍持有S型MDL锁。此时KILL QUERY只中断当前语句,事务本身没结束,锁还在。只有KILL CONNECTION才能真正释放MDL。
- 先用
SELECT * FROM information_schema.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = ?确认目标线程的TRX_STATE和TRX_STARTED - 再查
information_schema.PROCESSLIST对应ID的COMMAND是否为Sleep、TIME是否>300秒 - 若两者同时成立,且
TRX_QUERY为空,则KILL QUERY无意义,直接KILL CONNECTION
升级后必须立即调整的三个配置项
MySQL 8.0+默认wait_timeout=28800(8小时),对现代应用连接池极不友好——连接空闲8小时才断开,等于给MDL锁留足了“赖着不走”的时间窗口。
-
wait_timeout和interactive_timeout建议统一设为300(5分钟),与应用层连接池maxIdleTime对齐 - 启用
innodb_rollback_on_timeout=ON,避免锁等待超时后事务仍挂着 - 在应用启动脚本中强制设置
autocommit=1,杜绝隐式事务意外开启
Online DDL为何升级后反而更容易卡住
ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE在8.0+中仍需获取X型MDL锁,只是持有时间极短。但升级后,任何未提交事务(哪怕只执行了一条SELECT)都会让这个“短暂”变成“无限期等待”。
- 不要依赖
LOCK=NONE来规避MDL问题,它解决的是DML阻塞,不是MDL阻塞 - 执行前务必运行
SELECT * FROM information_schema.INNODB_TRX ORDER BY TRX_STARTED LIMIT 5,重点看TRX_STARTED和TRX_ISOLATION_LEVEL - 若发现
REPEATABLE READ事务启动时间异常早,且TRX_QUERY为空,说明应用层有BEGIN没COMMIT,这是升级后最常触发阻塞的模式
真正麻烦的从来不是DDL本身,而是那些在升级前被容忍、升级后被严格执行的“事务半开”状态——它们藏在连接池深处,不报错、不告警,只在DDL那一刻突然亮出MDL锁这张底牌。











