innodb_deadlock_detect是开关型参数,仅支持on/off,非频率控制器;死锁检测在加锁失败瞬间实时触发wait-for graph判定,毫秒级完成,无检测间隔;官方mysql 8.0不存在innodb_deadlock_detect_interval参数。

确认 innodb_deadlock_detect 是 ON 而不是调频率
死锁日志捕获不靠“检测频率”,因为 innodb_deadlock_detect 根本不是定时器——它是开关,只接受 ON 或 OFF。设为 ON(默认值)后,只要事务加锁失败进入等待,InnoDB 就**立刻**构建 wait-for graph 判定死锁,毫秒级完成。网上搜到的 innodb_deadlock_detect_interval 参数根本不存在于 MySQL 8.0 官方版本,配了会静默忽略。
必须开启 innodb_print_all_deadlocks 并确认日志落盘路径
即使死锁被实时检测到,不打开这个开关,MySQL 默认只保留最近一次死锁信息在 SHOW ENGINE INNODB STATUS 里,旧记录会被覆盖。要确保每次死锁都写进 error log:
-
SET GLOBAL innodb_print_all_deadlocks = ON;(MySQL 8.0.22+ 支持动态生效) - 检查 error log 路径:
SHOW VARIABLES LIKE 'log_error';,确保该文件可写(常见坑:目录权限不对、SELinux 拦截) - 注意:它只写到 error log,不写 slow log、general log 或其他地方
用 SHOW ENGINE INNODB STATUS 快速定位最新死锁现场
这个命令返回的文本里,真正有用的只有 LATEST DETECTED DEADLOCK 这一段。别被前面的 TRANSACTIONS、BUFFER POOL 等信息带偏:
- 重点对比两个事务各自的
HELD LOCKS(持有哪条记录、哪个索引) - 看各自
WAITING FOR THIS LOCK TO BE GRANTED(等谁、等哪一行) - 核对 SQL 是否用了不同索引(比如一个走
PRIMARY,另一个走idx_user_id)——这是应用层访问顺序不一致的铁证
避免误判:死锁日志 ≠ 锁等待超时日志
ERROR 1213(Deadlock found)和 ERROR 1205(Lock wait timeout)是两回事:
-
innodb_rollback_on_timeout控制的是 1205 是否回滚整个事务,跟死锁无关 - 死锁日志里一定包含两个及以上事务的完整锁状态,而锁等待超时日志里只有单个事务卡住的痕迹
- 如果反复看到 ERROR 1205 但
LATEST DETECTED DEADLOCK为空,说明问题不在死锁,而在事务过长或锁粒度太粗
真正难的不是开几个参数,而是从 LATEST DETECTED DEADLOCK 的几行 SQL 和锁记录里,还原出两个事务是怎么绕成环的——那才是唯一能定位代码问题的地方。











