insert被“waiting for table metadata lock”卡住,90%以上源于未提交事务持有s mdl锁;需查innodb_trx中trx_state='running'且trx_started超5分钟的记录,结合processlist和show engine innodb status确认是否空挂,再kill query或kill对应线程。

INSERT 被 Waiting for table metadata lock 卡住,90% 以上不是 INSERT 本身的问题,而是有别的连接正拿着该表的 MDL 锁没释放——最常见就是未提交的事务。
查哪些事务在“挂”着不提交
直接看 INNODB_TRX 里状态为 RUNNING 但 trx_started 时间异常久远的记录:
-
trx_state = 'RUNNING'且trx_started超过 5 分钟,基本可判定是应用端异常中断或忘记COMMIT/ROLLBACK - 重点核对
trx_isolation_level:如果是REPEATABLE READ,MDL 锁从BEGIN就持有了,哪怕只执行了一条SELECT,后续所有 DDL/DML 都会被拦 - 结合
PROCESSLIST看对应线程的COMMAND:若为Sleep,再看TIME是否 > 300 秒,且INFO为空 —— 这类就是典型“空挂事务”
确认它是否真在阻塞别人
不能光看 TIME 长就 KILL。先验证这个事务是否还在干活:
- 用
SHOW ENGINE INNODB STATUS\G查TRANSACTIONS段,找对应trx_id,看mysql tables in use和locked tables是否都为 0 —— 是则无实际操作,可安全终止 - 看
PROCESSLIST的STATE:Waiting for table metadata lock或Starting authentication是僵死信号;executing或sending data则需谨慎 - 优先执行
KILL QUERY {id}中断当前语句,观察是否恢复;若仍卡,再KILL {id}
为什么 SELECT 都能锁住 INSERT
很多人以为只有 UPDATE/DELETE 才加锁,其实只要显式开启事务(BEGIN),哪怕只跑一条 SELECT * FROM t WHERE id = 1,也会持有该表的 MDL 锁,直到事务结束。
- MySQL 5.5+ 的 MDL 是事务级的,不是语句级 —— 语句执行完不释放,得等
COMMIT或ROLLBACK - ORM 框架(如 aiomysql、SQLAlchemy)若配置了
autocommit=False,又没用上下文管理或手动提交,极易留下空挂事务 - DBA 工具(如 DBeaver)执行查询后关掉窗口,但连接未断开、事务未结束,锁就一直挂着
预防比排查更关键
升级后默认 wait_timeout=28800(8 小时),对连接池场景过于宽松,必须调低:
- 建议设为
wait_timeout = 300(5 分钟)、interactive_timeout = 300 - 应用层务必确保:显式事务配对使用
BEGIN/COMMIT或ROLLBACK,避免依赖连接自动关闭 - 云 RDS 要特别注意控制台“只读实例”开关,它会静默设置
super_read_only=ON,重启不恢复,仅改配置文件无效
真正难处理的不是锁本身,而是那个没人认领、查不到日志、连 INFO 都为空的“幽灵事务”——它往往藏在某个被遗忘的测试脚本、临时连接或异常退出的客户端里。











