mysql锁等待超时不会自动杀会话,innodb_lock_wait_timeout仅使被阻塞事务报错并回滚当前语句,连接仍存活;需结合max_execution_time与外部kill脚本识别并终止lock wait状态线程。

MySQL锁等待超时后不会自动杀会话,innodb_lock_wait_timeout只控制等待时长
很多人误以为设置 innodb_lock_wait_timeout 后,超时就会终止阻塞者或被阻塞的会话——其实它只让被阻塞的事务报错(ERROR 1205 (40001): Deadlock found when trying to get lock 或更常见的是 ERROR 1205 (40001) / ERROR 2013 (HY000)),然后回滚当前语句,**不会 kill 任何连接**。真正执行 SQL 的会话依然活着,可能继续持有锁、占用资源。
用 max_execution_time 配合 KILL 脚本实现“超时杀会话”
MySQL 原生不支持锁等待超时自动 KILL,但可组合以下手段逼近目标:
-
max_execution_time对 SELECT 有效(5.7.8+),设为略大于预期锁等待时间,超时后语句中断,但连接仍存活 —— 这只是第一步 - 需额外用外部脚本定期查
information_schema.INNODB_TRX和information_schema.PROCESSLIST,识别长时间处于LOCK WAIT状态的线程 - 对匹配的
ID执行KILL CONNECTION {id}(注意不是KILL QUERY,后者只停当前语句) - 示例判断逻辑(在监控脚本中):
SELECT ID FROM information_schema.PROCESSLIST p JOIN information_schema.INNODB_TRX t ON p.ID = t.TRX_MYSQL_THREAD_ID WHERE p.COMMAND = 'Sleep' AND t.TRX_STATE = 'LOCK WAIT' AND t.TRX_WAIT_STARTED
wait_timeout 和 interactive_timeout 不解决锁等待问题
这两个参数控制空闲连接的断开时间,和「正在等锁」完全无关。即使一个会话卡在 UPDATE ... WHERE id = 1 并死等行锁,只要它没断开、没发新命令,wait_timeout 就不会触发。别指望靠调小它们来清理锁等待会话。
生产环境更稳妥的做法:应用层主动设查询超时 + 重试 + 死锁捕获
比起依赖数据库侧杀会话,更可控的方式是:
- 在应用代码里给数据库驱动配置查询超时(如 JDBC 的
socketTimeout、queryTimeout) - 捕获
Deadlock found when trying to get lock(错误码 1213)和锁等待超时(1205 或连接中断异常) - 对可重试操作(如扣库存)做指数退避重试,而非放任会话僵死
- 避免长事务:在事务里不做 RPC、文件读写、sleep 等,减少锁持有时间
真正难处理的从来不是“怎么杀”,而是“为什么这个会话要等这么久”——查 SHOW ENGINE INNODB STATUS\G 里的 LATEST DETECTED DEADLOCK 和 TRANSACTIONS 段,往往比写 KILL 脚本更有价值。











