MySQL主从复制中binlog暴涨的根本原因是expire_logs_days默认为0(永不过期),且自动清理仅作用于非当前活跃日志;必须先确认log_bin=ON、各从库Relay_Master_Log_File最小值,再用PURGE BINARY LOGS或binlog_expire_logs_seconds(8.0+)安全清理,严禁rm删除。

MySQL主从复制中binlog暴涨,根本原因不是“写得太快”,而是“没人管清理”——expire_logs_days默认为0(永不过期),且自动清理只作用于非当前活跃日志,堆积的旧文件不会被自动回收。
确认binlog是否真在涨,还是压根没开
别一看到mysql-bin.*多就动手删。先连进 MySQL 执行:
-
SHOW VARIABLES LIKE 'log_bin';—— 返回ON才说明 binlog 确实启用;若为OFF,磁盘占满和 binlog 无关 -
SHOW BINARY LOGS;—— 看文件数量和总大小,File_size加起来超 2GB 就该干预了 -
SHOW MASTER STATUS;—— 记下当前正在写的文件名(如mysql-bin.000142),这是后续PURGE的安全上限
主从环境下哪些binlog能删,关键看Relay_Master_Log_File
不是“主库写了啥”,而是“从库读到哪”。每台从库都必须查:
- 登录从库,执行
SHOW SLAVE STATUS\G; - 重点看
Relay_Master_Log_File字段(不是Master_Log_File),它表示该从库已成功执行完的主库日志文件名 - 对比所有从库的这个值,取序号最小的那个(比如
mysql-bin.000135),这就是安全下限:你最多只能PURGE TO 'mysql-bin.000136'; - 漏掉任意一台从库(比如某台延迟严重但没查),删掉它还没读的日志,
Slave_IO_Running立刻变No,报错Got fatal error 1236
MySQL 8.0+ 必须用binlog_expire_logs_seconds,expire_logs_days已失效
在 8.0.11+ 版本中,expire_logs_days 被标记为 deprecated,设了也不生效。强行保留它可能白忙活:
- 临时生效:
SET GLOBAL binlog_expire_logs_seconds = 604800;(7 天),同时清掉旧参数:SET GLOBAL expire_logs_days = 0; - 永久生效:编辑
my.cnf的[mysqld]段,加两行:binlog_expire_logs_seconds = 604800expire_logs_days = 0 - 重启后验证:
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';必须返回你设的值 - 注意:自动策略只对「非当前正在写的 binlog」生效,已堆积的旧日志不会自动删,得手动
PURGE一次
PURGE后df -h没变化?Linux文件句柄还挂着
PURGE BINARY LOGS 执行成功,但 df -h 磁盘空间没释放,不是命令失败,而是 Linux 内核仍在保留已删除文件的句柄:
- 运行
lsof | grep deleted,如果看到大量mysql-bin.* deleted,就证实了这点 - 最稳妥解法:
FLUSH BINARY LOGS;(触发日志轮转),或重启 MySQL 服务 - 严禁用
rm直接删文件——MySQL 进程仍持有句柄,df不变,且会断主从、丢数据、甚至导致实例起不来
真正难的从来不是“怎么删”,而是判断“删到哪”——主从拓扑越复杂、延迟越不稳、从库越多,那个最小的 Relay_Master_Log_File 就越容易被忽略。每次清理前,必须人工确认每一台从库的状态,不能靠经验、不能靠“应该同步完了”。











