innodb_lock_wait_timeout只控制行锁等待超时,不控制死锁检测;死锁由InnoDB死锁检测器立即发现并回滚事务,与该参数无关。

innodb_lock_wait_timeout 设置后为什么死锁还是立刻报错?
因为 innodb_lock_wait_timeout 只控制「行锁等待超时」,不控制「死锁检测」。MySQL 一发现死锁,会立即回滚其中一方事务并抛出 Deadlock found when trying to get lock,根本不会等这个参数设定的时间。
常见错误现象:改了 innodb_lock_wait_timeout=120,但事务依然秒级报死锁,误以为配置没生效。
- 死锁由 InnoDB 的死锁检测器主动触发,和锁等待超时是两套机制
- 真正受
innodb_lock_wait_timeout影响的场景是:A 锁住某行,B 尝试更新同一行但 A 还没提交——这时 B 会卡住,直到超时或 A 提交/回滚 - 该参数对
SELECT ... FOR UPDATE、UPDATE、DELETE等加锁语句生效,对普通SELECT无效
怎么安全地修改 innodb_lock_wait_timeout?
不能只在 session 级临时改,生产环境必须确认全局行为是否一致。很多应用连接池复用连接,session 级设置容易被覆盖或遗忘。
- 查看当前值:
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout'; - 临时修改(重启失效):
SET GLOBAL innodb_lock_wait_timeout = 60;(需 SUPER 权限) - 永久修改:在
my.cnf的[mysqld]段下添加innodb_lock_wait_timeout = 60,然后重启 MySQL - 注意:已存在的连接仍沿用旧值,新连接才读取新配置;若用连接池,可能需要滚动重启应用
设成多大才算合理?
没有通用最优值,取决于业务事务平均执行时长和并发压力。设太大容易堆积阻塞,设太小又频繁报 Lock wait timeout exceeded。
- 默认值 50 秒,对多数 OLTP 业务偏长;建议先观察慢日志中
Rows_examined高且带锁操作的 SQL,估算其典型执行时间 - 若事务通常在 2 秒内完成,设为 10–15 秒较稳妥;高频短事务可压到 3–5 秒
- 超过 30 秒的等待基本说明有长事务、未提交事务或索引缺失导致锁范围过大,该优化 SQL 或事务逻辑,而不是盲目调高超时
- PHP 的
mysqli或 Python 的pymysql默认无连接级超时联动,应用层仍需设好connect_timeout和read_timeout,避免数据库超时了但客户端还在傻等
为什么 ALTER TABLE 也会被它卡住?
MySQL 8.0+ 的原地 DDL 多数情况不锁表,但某些操作(如修改列类型、添加全文索引)仍需获取元数据锁(MDL)和表级锁,而 innodb_lock_wait_timeout 不管 MDL——它只管 InnoDB 行锁。
- DDL 卡住通常是被活跃事务阻塞,比如有人正在查这张表且事务没结束,此时你看到的是
Waiting for table metadata lock,不是Lock wait timeout exceeded - 这类等待由
lock_wait_timeout(注意:没innodb_前缀)控制,它是 server 层参数,默认一年,几乎不会超时 - 真要查谁堵住了 DDL,用
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA='db' AND OBJECT_NAME='tbl';配合processlist
实际调参时最容易忽略的是:应用层没做重试或超时兜底,光调数据库参数只是把问题从“快失败”变成“慢失败”。锁等待时间再长,也掩盖不了事务设计不合理或索引缺失的本质。


















