必须开启 innodb_print_all_deadlocks=ON 并重启 MySQL,该参数默认关闭,仅配置不重启无效;生效后死锁详情追加至 log_error 指定的错误日志文件,可通过 SELECT @@innodb_print_all_deadlocks; 返回 1 确认。

怎么开启 MySQL 的死锁日志记录
默认情况下,MySQL 不会把每次死锁都写进错误日志,只记录最近一次(通过 SHOW ENGINE INNODB STATUS 查到的)。要持续捕获所有死锁,必须手动启用 innodb_print_all_deadlocks。
操作步骤很简单,但容易漏掉重启或权限问题:
- 编辑 MySQL 配置文件(通常是
/etc/my.cnf或/etc/mysql/my.cnf),在[mysqld]段下添加:innodb_print_all_deadlocks = ON - 重启 MySQL 服务(
systemctl restart mysql或service mysqld restart)——不重启配置不生效 - 确认是否生效:执行
SELECT @@innodb_print_all_deadlocks;,返回1表示已开启 - 查日志路径:
SHOW VARIABLES LIKE 'log_error';,然后用tail -f /var/log/mysql/error.log | grep -i deadlock实时观察
注意:该参数只影响日志输出,不影响死锁检测逻辑本身;日志量会随死锁频率上升,生产环境需配合日志轮转策略。
如何用 SHOW ENGINE INNODB STATUS 快速定位最近一次死锁
这是最常用、无需重启、即时可用的方法,但只能看到最后一次死锁详情,且内容混在大段状态输出中。
关键操作要点:
- 执行
SHOW ENGINE INNODB STATUS\G(务必加\G,否则输出难读) - 在输出里搜索
LATEST DETECTED DEADLOCK—— 这个区块包含两个事务的完整上下文:SQL、锁类型、索引、事务 ID、等待/持有关系 - 重点关注
*** (1) WAITING FOR THIS LOCK TO BE GRANTED和*** (2) HOLDS THE LOCK(S)两行,它们揭示了资源争夺的本质 - 该命令结果不会持久保存,下次死锁发生后会被覆盖,所以发现死锁后应立即复制保存
常见误操作:直接运行 SHOW ENGINE INNODB STATUS 不加 \G,导致输出挤成一行,根本没法定位关键词。
要不要开 InnoDB 锁监控(innodb_status_output_locks)
这个参数不是必须的,但对分析复杂死锁场景有帮助,尤其当涉及多个索引或间隙锁时。
它和死锁日志是两套机制:
-
innodb_print_all_deadlocks写日志,用于事后审计 -
innodb_status_output_locks影响SHOW ENGINE INNODB STATUS输出的详细程度,让锁信息更丰富 - 开启方式:
SET GLOBAL innodb_status_output_locks = ON;(无需重启) - 副作用:会使
SHOW ENGINE INNODB STATUS输出体积显著增大,频繁调用可能影响性能,建议仅在排查期临时开启
真正需要它的时候,是当你在 LATEST DETECTED DEADLOCK 里看到类似 RECORD LOCKS space id X page no Y n bits Z 却无法对应到具体行或索引时——开启后,输出会额外列出锁对应的 lock_trx_id、lock_mode、lock_table 等字段,方便关联 INFORMATION_SCHEMA.INNODB_LOCKS 表验证。
为什么光看日志还不够,还得查 INFORMATION_SCHEMA 表
死锁日志和 SHOW ENGINE INNODB STATUS 都是“事后快照”,而 INFORMATION_SCHEMA 表提供的是“当前实时锁视图”,两者互补才能还原完整链条。
最实用的组合查询是:
SELECT r.trx_id AS waiting_trx_id, r.trx_mysql_thread_id AS waiting_thread, r.trx_query AS waiting_query, b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_thread, b.trx_query AS blocking_query FROM information_schema.INNODB_LOCK_WAITS w INNER JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id;
这个查询直接暴露谁在等谁、等什么 SQL、阻塞方在执行什么——比翻日志快得多。但它有个硬限制:INNODB_LOCK_WAITS 只在锁等待真实发生时才有记录,一旦死锁被 MySQL 自动解开(即牺牲事务回滚后),这张表就清空了。所以它适合抓活锁,不适合复盘已发生的死锁。
容易忽略的一点:这些表依赖 information_schema 权限,普通应用账号通常没权限查,得用 DBA 账号或提前授权 SELECT 权限。


















