启用innodb_print_all_deadlocks = ON即可让每次死锁都写入错误日志;默认该参数为OFF,仅内存保留最后一次死锁,需通过SHOW VARIABLES确认状态,并结合log_error路径定位真实日志文件。

死锁日志默认不开启,先确认是否已启用
MySQL 的死锁信息不会自动记录到错误日志,除非显式开启 innodb_print_all_deadlocks。默认它是 OFF,所以你查不到任何死锁日志——不是查得不对,是根本没写。
检查当前状态:
SHOW VARIABLES LIKE 'innodb_print_all_deadlocks';
如果返回 OFF,那最近一次死锁大概率没被记录,直接翻错误日志只会看到一句模糊的 Deadlock found when trying to get lock,没有堆栈和事务详情。
- 设为
ON后,每次死锁都会完整打印到error_log(不是 slow log,也不是 general log) - 修改需重启或动态生效:
SET GLOBAL innodb_print_all_deadlocks = ON;(但重启后失效,建议写进my.cnf的[mysqld]段) - 注意:开启后日志体积增长较快,生产环境可短期打开排查,不建议长期常开
找到真正的 error_log 路径再 grep
很多人卡在“找不到日志”,其实是因为压根不知道 MySQL 当前用的是哪个 error log 文件。它不一定是 /var/log/mysql/error.log,尤其在 Docker、Homebrew 或自编译部署下路径差异很大。
查真实路径:
SHOW VARIABLES LIKE 'log_error';
返回值比如 /usr/local/var/mysql/localhost.err,这才是你要翻的日志文件。
- 死锁日志块以
*** (1)和*** (2)开头,包含事务 ID、SQL、锁类型、等待/持有关系 - 用
grep -A 20 -B 5 "Deadlock detected" /path/to/error.log快速定位最近几条(-A/-B控制上下文行数) - 如果日志启用了轮转(如
mysql_safe自动切割),记得检查error.log.1、error.log.2.gz等归档文件
没开 innodb_print_all_deadlocks?试试 INFORMATION_SCHEMA 表
MySQL 5.6.28+ 提供了 INFORMATION_SCHEMA.INNODB_TRX 和 INNODB_LOCK_WAITS,但它们只反映「当前」阻塞状态,死锁发生后瞬间回滚,事务已不存在——所以这些表查不到历史死锁。
唯一能间接佐证的,是错误日志里残留的那句提示:
2024-05-20T10:12:34.567890Z 12345 [ERROR] [MY-012877] [InnoDB] Transaction was deadlocked...
这行有时间戳,但没细节。靠它只能知道“发生过”,无法分析根因。
-
SHOW ENGINE INNODB STATUS\G输出里的LATEST DETECTED DEADLOCK段落,只保留最后一次死锁的完整信息,但仅限当前实例内存中未被覆盖时可见 - 执行该命令后立即看,别等几分钟——它可能已被新死锁覆盖
- 输出里
WAITING FOR THIS LOCK TO BE GRANTED和HOLDS THE LOCK(S)是关键线索,对应哪条 SQL、什么索引、什么隔离级别
用 pt-deadlock-logger 抓实时死锁(适合线上长期监控)
Percona Toolkit 的 pt-deadlock-logger 能轮询 SHOW ENGINE INNODB STATUS,把每次捕获到的 LATEST DETECTED DEADLOCK 写进指定表或文件,比人工盯日志靠谱得多。
基础用法:
pt-deadlock-logger --host=localhost --user=root --password=xxx h=localhost,D=test,t=deadlocks
它会自动建表 deadlocks 并持续插入结构化记录。
- 每行含时间、事务 ID、SQL、锁模式、等待对象,支持按时间范围查询
- 注意权限:需要
PROCESS权限读取 InnoDB 状态,INSERT权限写目标表 - 别用 root 长期跑,建议单独建账号并最小授权
- 如果
SHOW ENGINE INNODB STATUS被其他高频率监控工具刷屏,可能导致漏抓——它依赖轮询间隔和状态刷新时机
死锁日志不是“查一下就有”,它依赖配置、路径、时效性三重条件。最常被忽略的是:以为开了 general log 就能看见死锁,其实完全无关;或者翻错了日志文件,却反复 grep 一个空文件。


















