最可靠方式是执行select @@innodb_lock_wait_timeout;若需查所有活跃连接真实值,则用select thread_id, variable_value from performance_schema.variables_by_thread where variable_name = 'innodb_lock_wait_timeout'。

别全局硬调,优先用 SET SESSION 配合连接池初始化 SQL,再优化索引与事务——否则参数再准也白搭。
怎么查当前会话实际生效的值?
别信配置文件或 SHOW VARIABLES 的模糊结果,它可能来自全局默认、连接池初始化时刻,甚至你上次手动 SET 过的残留。最可靠的方式是执行:
SELECT @@innodb_lock_wait_timeout;
如果用的是 HikariCP、Druid 或 pymysql pool,这个值大概率是连接建立那一刻从全局继承来的,不是你临时 SET SESSION 改的。要查所有活跃连接的真实值,得用:
SELECT THREAD_ID, VARIABLE_VALUE FROM performance_schema.variables_by_thread WHERE VARIABLE_NAME = 'innodb_lock_wait_timeout';
SET GLOBAL 和 SET SESSION 到底影响谁?
这两个命令作用范围完全不同,混淆会导致“以为改了,其实没起效”:
-
SET SESSION innodb_lock_wait_timeout = 5:只改当前连接,适合在支付类关键事务前显式收紧;连接池复用的连接不受影响 -
SET GLOBAL innodb_lock_wait_timeout = 10:只对后续新建的连接生效,已存在的连接(包括连接池里正在复用的)完全不变 - 没有 SUPER 权限?那就只能改
my.cnf+ 重启,或退而求其次,在应用层每个事务开头加SET SESSION innodb_lock_wait_timeout = 5
设成多少秒才算合理?
不是看“建议值”,而是对齐业务响应边界和重试能力:
- 金融类强一致操作(如扣款):
innodb_lock_wait_timeout = 5—— 错误需秒级暴露,留给应用重试窗口 - 普通 Web 业务(如订单创建):
innodb_lock_wait_timeout = 15—— 多数正常 DML 应在毫秒级完成,15 秒能覆盖临时抖动 - 离线任务或后台管理:
innodb_lock_wait_timeout = 300—— 但必须确保事务本身不长期持有锁 - 绝对不要设为 0(无限等待)或 >300(5 分钟以上),前者易引发连接堆积,后者掩盖真实瓶颈
注意:设得太小(如 2 秒)容易因网络抖动或 IO 延迟误超时;设太大(如 60 秒)则前端早超时(Nginx proxy_read_timeout=60),后端还在干等,线程池被占满。
为什么调了还是报 Lock wait timeout exceeded?
这个参数只管「等锁」,不管「锁太久」或「执行慢」:
-
UPDATE ... WHERE unindexed_column = ?扫全表,持锁几十秒——innodb_lock_wait_timeout不会打断它,只会让别人等它时超时 - 频繁报错,第一反应不该是调大,而是查
SHOW ENGINE INNODB STATUS\G里 waiting 的是谁、被谁堵着,再看information_schema.INNODB_TRX找 TRX_STARTED 超 60 秒的长事务 - 死锁错误(
ERROR 1213 (HY000): Deadlock found)和这个参数无关,InnoDB 自己秒级检测并回滚,根本不会等到超时
真正容易被忽略的是:参数再细,也救不了没索引的查询、没 commit 的事务、或者存储过程里一个没控制的 SLEEP(60) —— 它们都不触发锁等待超时,却直接拖垮系统。











