必须改配置文件并重启才真正生效,SET GLOBAL仅对新连接临时有效且重启丢失;日志输出至log_error指定的错误日志,需确保路径可写、log_error_verbosity≥3且log_error_services包含log_sink_internal。

必须改配置文件并重启,SET GLOBAL 只是假象,别信它能长期生效。
为什么 SET GLOBAL innodb_print_all_deadlocks = ON 不起作用
这个变量看起来可动态设置,但实际是“只对新连接生效”的伪动态变量。生产环境里连接池复用连接,几乎不会新建连接去继承这个值;MySQL 一重启,设置就清空。更关键的是,innodb_print_all_deadlocks 在内部被标记为只读(read-only),SET GLOBAL 命令能执行成功只是兼容性兜底,并不真正改变引擎行为。
常见错误现象:
- 执行
SET GLOBAL innodb_print_all_deadlocks = ON;后查SELECT @@innodb_print_all_deadlocks;返回ON,但错误日志里始终没死锁记录 - 重启 MySQL 后变量变回
OFF,误以为“之前设过就该一直有效”
真正生效的三步操作
缺一不可,漏掉任意一步都会白配:
- 编辑 MySQL 配置文件:
/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf,在[mysqld]段下添加一行:innodb_print_all_deadlocks = ON - 确认
log_error路径可写:先运行SHOW VARIABLES LIKE 'log_error';查路径,再执行ls -ld $(dirname $(mysql -Nse "SELECT @@log_error")),确保属主是mysql用户且有写权限 - 重启服务:
systemctl restart mysql(或service mysqld restart),之后立刻验证:SELECT @@innodb_print_all_deadlocks;必须返回ON
死锁日志到底输出到哪?为什么 grep 不到
它不会单独建文件,只追加进 MySQL 的错误日志(error log),但很多人卡在这儿:
- 路径不是固定值,可能是
/var/log/mysql/error.log、/var/lib/mysql/hostname.err或/usr/local/mysql/data/mysqld.local.err,必须用SHOW VARIABLES LIKE 'log_error';确认 - 如果返回空或
NULL,说明错误日志被禁用(比如 systemd 配置了StandardError=journal),此时死锁信息直接丢弃,不会落盘 - MySQL 8.0 还要检查
log_error_services是否包含log_sink_internal:运行SELECT @@log_error_services;,结果里必须含log_sink_internal,否则即使开了innodb_print_all_deadlocks也写不进去
开启后怎么看日志和验证效果
别等真出问题才翻日志,主动触发一次测试最可靠:
- 开两个会话,分别执行交叉更新(如事务 A 更新 row1 再更新 row2,事务 B 反过来),制造一次人为死锁
- 立刻用
tail -f $(mysql -Nse "SELECT @@log_error") | grep -i "deadlock"实时观察 - 日志里会出现完整的
LATEST DETECTED DEADLOCK块,包含两个事务的 SQL、持有的锁、等待的锁、线程 ID 和堆栈——这才是你真正需要的诊断信息 - 顺便查下
SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks';,数值递增说明捕获已工作
最容易被忽略的是 log_error_services 和目录写权限,这两个点不检查,配得再准也看不到日志。











