show engine innodb status仅保留最近一次死锁是innodb设计的单槽覆盖机制,非bug;要捕获全部死锁,必须启用innodb_print_all_deadlocks=1并写入error log。

SHOW ENGINE INNODB STATUS 只显示最后一次死锁是设计限制
MySQL 的 SHOW ENGINE INNODB STATUS 命令内部只缓存最近一次死锁的完整上下文,不是日志轮转机制,而是单槽覆盖——下一次死锁发生时,前一次内容直接被丢弃。这不是 bug,是 InnoDB 的轻量级现场快照策略,不消耗额外存储或影响性能。
所以你看到“只有两个事务”,不是解析问题,而是它本来就没存更多。哪怕一小时内发生 50 次死锁,执行这条命令也只会返回第 50 次的 LATEST DETECTED DEADLOCK 区块。
抓取全部死锁必须开启 innodb_print_all_deadlocks = 1
要让每次死锁都落盘,唯一可靠方式是启用全局配置项:innodb_print_all_deadlocks。默认值为 OFF,生产环境几乎总是关闭的。
- 确认当前状态:
SELECT @@innodb_print_all_deadlocks;—— 返回0表示未开启 - 临时开启(重启失效):
SET GLOBAL innodb_print_all_deadlocks = ON; - 永久生效:在
my.cnf的[mysqld]段下添加innodb_print_all_deadlocks = 1,然后重启或热加载(RDS 支持参数模板更新) - 务必检查错误日志路径可写:
SHOW VARIABLES LIKE 'log_error';,再确认 MySQL 进程用户(如mysql)对该文件有追加权限
从错误日志里提取多段死锁不能靠 “LATEST DETECTED DEADLOCK”
开启 innodb_print_all_deadlocks 后,每段死锁记录以 *** (1) TRANSACTION: 开头,结尾无固定标记,但必含 RECORD LOCKS 或 TABLE LOCK 字样。常见错误是用 grep "LATEST DETECTED DEADLOCK" 去搜错误日志——这个字符串只存在于 SHOW ENGINE INNODB STATUS 输出中,错误日志里根本不存在。
正确提取方式:
- 按锁结构定位:
grep -A 50 -B 5 "RECORD LOCKS.*space id" /var/log/mysql/error.log - 实时监控新增死锁:
tail -f /var/log/mysql/error.log | grep -A 30 -B 5 "RECORD LOCKS" - 如果日志量大,建议配合时间范围过滤,例如先用
grep "2026-09-28.*deadlock" /var/log/mysql/error.log锁定日期段
MySQL 8.0+ 注意 performance_schema.data_locks 不包含死锁历史
performance_schema.data_locks 是实时锁视图,反映当前持有/等待状态,不是死锁归档。它无法告诉你“刚才谁和谁死了”,只能回答“现在谁卡着谁”。想回溯历史死锁,依然只能依赖开启 innodb_print_all_deadlocks 后的错误日志。
另外,INFORMATION_SCHEMA.INNODB_LOCKS 和 INNODB_LOCK_WAITS 在 MySQL 8.0 已被移除,硬查会报错。别在新版本里写脚本依赖这两个表。
真正容易被忽略的是:即使开了 innodb_print_all_deadlocks,如果错误日志本身被 logrotate 切割或清空过,历史死锁就永远丢失了。定期归档 + 权限校验比调参更重要。











