lock_wait_timeout 控制元数据锁(MDL)等待超时,默认31536000秒(一年),影响DDL操作;innodb_lock_wait_timeout 仅控制InnoDB行级锁等待,默认50秒,对MDL无效。

MySQL 8.0 的 lock_wait_timeout 和 innodb_lock_wait_timeout 完全不是一回事
很多人一看到报错里有 “lock wait timeout”,就去改 innodb_lock_wait_timeout,结果发现 ALTER TABLE 还是卡住、CREATE INDEX 还是等半天——因为那是元数据锁(MDL)在作祟,而 innodb_lock_wait_timeout 只管 InnoDB 行锁,对 MDL 完全无效。
lock_wait_timeout 才是控制 MDL 等待的参数,MySQL 8.0 默认值飙升到 31536000 秒(一年),相当于“永不超时”。这会让 DDL 操作长期挂起,阻塞所有后续查询(包括普通 SELECT),极易引发雪崩。
- 查当前值:
SELECT @@lock_wait_timeout; - 临时生效(当前会话):
SET lock_wait_timeout = 60; - 全局生效(新连接):
SET GLOBAL lock_wait_timeout = 60; - 永久生效:在
my.cnf的[mysqld]段下加lock_wait_timeout = 60,然后重启 MySQL
为什么改了 lock_wait_timeout 还是被 DDL 卡住?
因为这个参数只影响「新申请 MDL 的线程」,不中断已持有的 MDL。比如一个长事务正在执行 SELECT,它已经持有了 SHARED_READ 锁;此时你执行 ALTER TABLE 要申请 EXCLUSIVE 锁,就会在 lock_wait_timeout 时间内等待——但如果那个长事务迟迟不结束,等待就真会耗尽超时时间,然后报错。
更常见的情况是:lock_wait_timeout 设得太大(比如默认的一年),导致应用层 HTTP 请求早已超时断开,而 MySQL 还在傻等,连接堆积、线程耗尽。
- 线上建议设为
30–60秒,和应用层 read_timeout 对齐 - 必须配合监控:查
performance_schema.threads中PROCESSLIST_INFO为空但PROCESSLIST_STATE为Waiting for table metadata lock的线程 - 快速定位阻塞源:
SELECT * FROM performance_schema.metadata_locks ml JOIN performance_schema.threads t ON ml.OWNER_THREAD_ID = t.THREAD_ID WHERE ml.OBJECT_SCHEMA = 'your_db' AND ml.LOCK_STATUS = 'PENDING';
DDL 卡住时,别只盯着 lock_wait_timeout
真正拖住 DDL 的,90% 是未提交事务、慢查询或客户端连接假死。InnoDB 在执行原地 DDL 前,必须确保没有活跃事务正在访问该表(哪怕是只读),否则就卡在 MDL 获取阶段。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
- 先查长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60; - 再查活跃连接:
SHOW PROCESSLIST;,重点看Command是Sleep但Time很大的连接(可能是应用没关连接) - 别忽略隐式事务:某些 ORM 或驱动在 autocommit=OFF 模式下执行了 SELECT 后没 COMMIT,也会持有 MDL
- MySQL 8.0+ 支持
ALTER TABLE ... ALGORITHM=INSTANT,对某些变更(如加列)完全不锁表,优先考虑
innodb_deadlock_detect 关掉能缓解 MDL 等待吗?
不能。死锁检测器只处理事务间循环等待行锁的场景,和 MDL 完全无关。innodb_deadlock_detect 关闭后,行锁死锁会等到 innodb_lock_wait_timeout 超时才回滚,但 MDL 阻塞仍由 lock_wait_timeout 控制。
唯一相关的是:高并发下频繁的死锁检测会抢 CPU,间接拖慢 MDL 排队速度。但这属于次要因素,优先级远低于清理长事务和调低 lock_wait_timeout。
真正容易被忽略的点是:MySQL 8.0 的 MDL 锁升级逻辑更严格,SELECT 和 UPDATE 拿的锁类型不同,但都可能阻塞 DDL;而应用层很少意识到一次简单的查询也可能成为 DDL 的“钉子户”。










