innodb_lock_wait_timeout仅控制行锁等待超时(默认50秒),不解决锁持有过长问题;设太小致频繁报错,设太大掩盖隐患,需配合查长事务、加索引、拆事务等根治。

别直接改全局值到 30 或 60 秒——它治标不治本,还可能掩盖真正的锁持有过长问题。
为什么改了 innodb_lock_wait_timeout 还是报 Lock wait timeout exceeded
这个参数只控制「等锁超时」,不解决「为什么别人一直不放锁」。常见误判点:
- 看到错误就调大参数,但真正卡住的是一个没提交的长事务:SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - TRX_STARTED) > 60
- 应用层 JDBC 配了
socketTimeout=5000,客户端 5 秒就断了,MySQL 根本没机会抛出锁超时错误 - UPDATE 语句没走索引,触发全表扫描+间隙锁升级,等待范围远超单行,
innodb_lock_wait_timeout压根不是瓶颈 - 错误其实是
ERROR 1205 (40001): Deadlock found when trying to get lock,那是死锁检测机制干的,和这个参数无关
OLTP 场景下该设成多少才不踩坑
高并发写入业务(如订单、库存扣减)建议设为 15 秒起步,而非拍脑袋定 30 或 60。理由很实际:
- 设太小(如
5):网络抖动、临时 IO 延迟都可能触发误超时,重试风暴导致连接数和 CPU 飙升 - 设太大(如
300):前端早超时了(比如 Nginxproxy_read_timeout=60),后端还在干等,线程池被占满 - 必须和应用层重试逻辑对齐:有幂等重试时可放宽到
25;无重试则别超过15 - 绝对不要设为
0:官方明确不推荐,等于无限等待,极易引发连接堆积
怎么改才真正生效,而不是“以为改了”
SET GLOBAL innodb_lock_wait_timeout = 15 只对新连接生效,已连上的旧连接仍用原值。线上服务 reload 配置也不触发重连,所以你以为改了,其实没起效。
- 调试单条 SQL:用
SET SESSION innodb_lock_wait_timeout = 15,仅当前连接有效 - 让所有新连接立刻用新值:执行
SET GLOBAL innodb_lock_wait_timeout = 15,但需配合应用连接池主动回收旧连接(如 HikariCP 的maxLifetime) - 永久生效:必须写进
/etc/my.cnf的[mysqld]段,且重启或执行mysqladmin reload(部分版本支持)
比调参更关键的三件事,90% 的人一上来就跳过
锁超时本质是资源竞争暴露出来的症状,参数只是调节痛感的刻度盘。真正要盯紧的:
- 谁在持锁?查
information_schema.INNODB_TRX找TRX_STATE = 'RUNNING'且TRX_STARTED超 60 秒的事务,定位对应应用代码 - 锁为什么范围这么大?用
EXPLAIN看 UPDATE/DELETE 是否走了索引,避免type: ALL导致全表加锁 - 事务粒度是否合理?一个事务里混着 HTTP 调用、日志写入、数据库更新,锁持有时间完全不可控——非核心操作得挪到事务外
最常被忽略的一点:innodb_lock_wait_timeout 单位是秒,不是毫秒;默认是 50,不是 50ms;它对分布式死锁、跨库锁、Redis 锁完全无效——那些得靠应用层协调,MySQL 根本不感知。











