ddl卡住主因是元数据锁(mdl)等待,而非innodb_lock_wait_timeout控制的行锁;真正决定ddl等待超时的是lock_wait_timeout,默认31536000秒,需设为30–60秒并与应用层超时对齐,同时优先排查未提交事务、慢查询或假死连接等阻塞源。

DDL卡住不是因为行锁超时,而是元数据锁(MDL)在等
MySQL 8.0 执行 ALTER TABLE 或 CREATE INDEX 时卡住并报 Lock wait timeout exceeded,大概率不是 innodb_lock_wait_timeout 导致的——那个参数只管 InnoDB 行级锁,对 DDL 完全无效。真正拦住 DDL 的是元数据锁(MDL),它控制表结构变更的并发安全,而它的等待超时由 lock_wait_timeout 控制,默认值高达 31536000 秒(一年),相当于“永不放弃”。
为什么改了 innodb_lock_wait_timeout 没用?
因为 DDL 不走 InnoDB 行锁路径。你看到错误里有 “lock wait timeout”,就去调 innodb_lock_wait_timeout,结果 ALTER TABLE 还是卡着不动——这是典型误判。DDL 阶段要获取 MDL EXCLUSIVE 锁,但只要表上有任何活跃事务(哪怕只是个 SELECT),就会阻塞它;而 innodb_lock_wait_timeout 对这种阻塞毫无影响。
-
innodb_lock_wait_timeout:只作用于 UPDATE/DELETE/INSERT 等语句等待行锁的场景 -
lock_wait_timeout:才决定 DDL 等待 MDL 的最大时长,必须显式设置 - 两者数值可以不同,且互不干扰;线上建议设为 30–60 秒,与应用层 read_timeout 对齐
DDL 卡住时,90% 的根因不在锁参数本身
真正拖住 DDL 的,几乎总是未提交事务、慢查询或假死连接。InnoDB 在执行原地 DDL 前,必须确保没有事务正在访问该表(包括只读),否则就卡在 MDL 获取阶段。排查优先级应是:
- 查长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60 - 查空挂线程:
SHOW PROCESSLIST中Command = 'Sleep'且Time很大的连接 - 查阻塞源:
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'
临时生效和永久生效的区别很关键
SET lock_wait_timeout = 60 只对当前会话有效,DDL 启动后才生效;SET GLOBAL lock_wait_timeout = 60 影响后续新连接,但不会中断已卡住的 DDL。真正想让已有 DDL 快速失败,得先定位并 KILL 掉持有 SHARED_READ 锁的源头事务(比如那个没提交的 SELECT),而不是等超时。
容易被忽略的是:即使你把 lock_wait_timeout 设得很小,如果阻塞源一直不释放 MDL,DDL 就真会立刻失败——这不是配置问题,是业务逻辑或连接管理出了漏洞。











