innodb_lock_wait_timeout是唯一直接干预锁等待的参数,仅控制事务等待行锁的最长时间(默认50秒),超时即报错回滚当前语句;它不约束慢查询、sleep或外部调用,高并发建议设为10~25秒;wait_timeout对长事务无效,真正可靠的防护需结合客户端query timeout、存储过程手动耗时检查及业务层兜底。

innodb_lock_wait_timeout 是唯一能直接干预锁等待的参数
MySQL 没有“事务执行超时”机制,innodb_lock_wait_timeout 控制的只是「等锁」这一环节——当事务 A 尝试更新某行,而该行正被事务 B 锁住未提交,A 最多等 innodb_lock_wait_timeout 秒,超时就报 Lock wait timeout exceeded 并回滚当前语句(不是整个事务)。
它不防慢查询、不防 SLEEP、不防 HTTP 调用,只对行锁等待生效。
默认值 50 秒偏高,高并发场景建议设为 10~25 秒:SET SESSION innodb_lock_wait_timeout = 15;
注意:全局修改需 SET GLOBAL innodb_lock_wait_timeout = 15;,但不会影响已有连接。
wait_timeout 对长事务完全无效,别误配
wait_timeout 只在连接空闲时倒计时,只要事务里执行了任何 SQL(哪怕只是 SELECT 1),计时就重置。一个开了事务却卡在外部 API 调用上的连接,wait_timeout 压根不会断它。
所以:
• 别指望靠调小 wait_timeout 来杀长事务
• interactive_timeout 更没用——存储过程调用走的是非交互式连接
• 它真正防的是“连上后啥也不干”,不是“事务挂起”
必须在存储过程里手动埋点检测总耗时
靠 MySQL 自身参数无法限制事务总执行时间,得自己写逻辑:
• 开头记起点:SELECT NOW() INTO @start_time;
• 关键步骤后检查:IF TIMESTAMPDIFF(SECOND, @start_time, NOW()) > 30 THEN ROLLBACK; LEAVE proc_label; END IF;
• 所有 START TRANSACTION 必须包裹在 DECLARE EXIT HANDLER FOR SQLEXCEPTION 里,否则异常跳出时事务悬空
• 绝对避免在事务内调 SLEEP()、GET_LOCK() 或发起外部请求——这些操作不触发锁等待,innodb_lock_wait_timeout 彻底失效
客户端 query timeout 是最可靠的一道防线
应用层设置语句级超时,能在任意 SQL 卡住时立刻中断连接,比存储过程内检测更及时:
• Java JDBC:PreparedStatement.setQueryTimeout(30)
• Python pymysql:cursor.execute(sql, timeout=30)
• Go database/sql:ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + db.QueryContext(ctx, ...)
这个 timeout 触发后,驱动会主动 close 连接,释放资源,且不依赖 MySQL 内部机制
真正容易被忽略的是:innodb_lock_wait_timeout 管不了执行慢,wait_timeout 管不了事务挂起,只有客户端 query timeout + 存储过程内手动耗时检查 + 业务代码兜底 commit/rollback,三者缺一不可。











