启用innodb_print_all_deadlocks = on即可让每次死锁都追加写入error log,而非仅保留最后一次;因mysql 5.7默认仅在内存缓存最近一次死锁快照供show engine innodb status查看,历史记录不持久、不归档、不落盘。

直接结论:设 innodb_print_all_deadlocks = ON,死锁就会每次追加写入 error log,而不是只留最后一次。
为什么 SHOW ENGINE INNODB STATUS 只能看到“上一次”死锁?
MySQL 5.7 的 InnoDB 在内存中只缓存最近一次死锁的完整上下文,SHOW ENGINE INNODB STATUS\G 输出的 LATEST DETECTED DEADLOCK 区块就是这个快照——它不持久、不归档、不自动落盘。你线上连续发生五次死锁,执行这条命令可能只看到第五次,前四次彻底丢失。
这不是配置遗漏,是默认行为。想追溯历史,必须让日志“落地”。
怎么开启并确认生效?
只需一个动态变量,但注意作用域和验证方式:
- 临时开启(立即生效,重启失效):
SET GLOBAL innodb_print_all_deadlocks = ON; - 永久生效:在
my.cnf的[mysqld]段下添加innodb_print_all_deadlocks = ON,然后重启 MySQL - 验证是否成功:
SELECT @@global.innodb_print_all_deadlocks;返回1即表示已启用 - 别漏掉日志基础配置:
log_error_verbosity建议设为3(默认值),否则低等级日志可能过滤掉死锁详情:SET GLOBAL log_error_verbosity = 3;
死锁日志写到哪儿?怎么看?
日志会追加到 MySQL 的 error log 文件里,路径由 log_error 变量决定(常见如 /var/log/mysql/error.log 或 /data/mysql/error.log):
- 先查路径:
SHOW VARIABLES LIKE 'log_error'; - 再查内容:
tail -n 100 /path/to/your-error.log | grep -A 20 -B 5 "DEADLOCK" - 典型开头是:
*** (1) TRANSACTION:,后面跟着事务 ID、SQL、锁类型(Record lock/Gap lock)、等待链和时间戳 - 注意:日志是纯文本块,用空行分隔,不是 JSON,也不是结构化格式;靠关键词定位,别指望自动高亮
容易被忽略的关键点
这个开关本身很简单,但真正卡住人的从来不是“开不开”,而是后续分析:
-
innodb_print_all_deadlocks只对“被检测到的死锁”生效;如果innodb_deadlock_detect = OFF,连检测都关了,自然不会打印 - 日志里不会直接告诉你哪条 SQL 是“罪魁祸首”,得自己比对两个事务的
trx_started和trx_wait_started时间戳,还原加锁顺序 - 高频死锁场景下,日志量暴增,可能一天几十 MB;务必配合
logrotate避免磁盘打满 - 它不替代
SHOW ENGINE INNODB STATUS——后者仍是看“当前卡在哪”的第一入口;而这个参数输出的是“事后证据链”,用于归因,不是实时诊断
真正难的不是打开开关,是从日志里拼出两个事务的加锁路径。那才是死锁根源所在。











