根本原因是MySQL 8.0暴露了旧版本中“装睡”的未提交悬挂事务:它们在PROCESSLIST中显示为Sleep但INNODB_TRX中trx_state='RUNNING'、trx_query IS NULL,持续持有MDL锁,导致DDL和DML阻塞;需通过INNODB_TRX与metadata_locks联合定位,并优先KILL QUERY再KILL CONNECTION安全终止。

升级 MySQL 8.0 后元数据锁(MDL)等待暴增,根本不是锁机制变严了,而是旧版本里“装睡”的悬挂事务在新版本下彻底暴露——它们状态是 Sleep,但 trx_state = 'RUNNING'、trx_query IS NULL,MDL 锁一直挂着不放,卡死所有 DDL 和后续 DML。
为什么 SHOW PROCESSLIST 找不到阻塞源
真正持锁的线程在 SHOW PROCESSLIST 里往往显示为:Command = 'Sleep'、State 为空、Time 很大(比如 1200 秒)。它不执行语句,所以不显现在活跃查询列表中;但它在 INNODB_TRX 里仍是 trx_state = 'RUNNING',说明事务已启动、语句早执行完、但没提交——MDL 锁从 BEGIN 那一刻起就挂死了。
原因包括:
- Python/Java 客户端(如
pymysql、aiomysql)默认autocommit=False,执行完SELECT后既不commit()也不close() - DBA 或脚本手动
BEGIN后忘记COMMIT,连接保持空闲但事务未结束 -
mysqldump --single-transaction进程未完成,对所有涉及表持续持有MDL_SHARED_READ
如何准确定位悬挂事务并安全终止
不能只看 Time > 600 就 KILL,必须交叉验证是否真在空转:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 查
information_schema.INNODB_TRX,按trx_started倒序,重点筛选:trx_autocommit = 0、trx_state = 'RUNNING'、trx_query IS NULL - 用查到的
trx_mysql_thread_id关联performance_schema.threads和performance_schema.metadata_locks,确认该线程是否对目标表持有LOCK_TYPE = 'SHARED_READ'或'SHARED_WRITE' - 执行
SHOW ENGINE INNODB STATUS\G,在TRANSACTIONS部分找对应trx_id,看mysql tables in use和locked tables是否都为 0 - 先执行
KILL QUERY thread_id(对Sleep连接虽无效,但可排除它正在跑长查询的可能),等 10–20 秒;若状态无变化,再执行KILL CONNECTION thread_id
为什么改了 lock_wait_timeout 还是卡住
lock_wait_timeout 控制的是「新申请 MDL 的线程」最多等多久,默认值是 31536000 秒(一年),相当于永不超时。但它不中断已持有的 MDL——比如一个长事务已持有 SHARED_READ,你执行 ALTER TABLE 要申请 EXCLUSIVE 锁,就会卡满这个超时时间才报错。
线上建议设为 30–60 秒,并同步调整:
- 全局:
SET GLOBAL lock_wait_timeout = 60,或写入my.cnf的[mysqld]段并重启 - 应用层
read_timeout必须与之对齐,否则客户端早已断开,MySQL 还在傻等 - 配合监控查
performance_schema.threads中PROCESSLIST_STATE = 'Waiting for table metadata lock'的线程
wait_timeout 默认值才是隐患源头
MySQL 8.0 默认 wait_timeout = 28800(8 小时),而 5.7 在连接空闲后常被自动断开。升级后这个宽松设置让悬挂事务“睡得更久、锁得更死”。必须立刻调整:
- 全局设
wait_timeout = 300(5 分钟)和interactive_timeout = 300 - 应用层连接池也要匹配:如 HikariCP 的
idleTimeout、maxLifetime - ORM 框架(如 Hibernate)需确保每次事务边界清晰,避免隐式开启事务后遗漏提交
最易被忽略的是:DDL 卡住时,90% 的根因不在锁参数本身,而在未提交事务、慢查询或客户端假死。排查顺序永远是:先查 INNODB_TRX,再查 metadata_locks,最后动 lock_wait_timeout——调参治标,清悬挂事务才治本。

















