mysql 8.0+ 必须配置 binlog_expire_logs_seconds(如604800秒)才能自动清理binlog,expire_logs_days已废弃且默认为0(永不清除),需同时设为0避免冲突,并配合max_binlog_size控制单文件大小。

必须设自动清理参数,否则 binlog 永远不删——MySQL 默认 expire_logs_days = 0,等同于永久保留。
确认 binlog 是否开启及当前过期策略
别猜,先查实况。很多问题其实根本没开 binlog,或开了但参数压根没生效:
- 运行
mysql -uroot -p -e "SHOW VARIABLES LIKE 'log_bin';",返回ON才说明已启用 - 执行
SHOW VARIABLES LIKE 'expire_logs_days';或SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';,若值为0或空,代表未启用自动清理 - 用
SHOW BINARY LOGS;看文件数量和总大小,File_size列加起来超 2GB 就该动手了
MySQL 8.0+ 必须用 binlog_expire_logs_seconds
MySQL 8.0 开始,expire_logs_days 已被标记为 deprecated,设了也不生效——这不是 bug,是官方明确弃用。强行写进配置或 SET GLOBAL 都可能白忙活。
- 7 天对应秒数是
604800,执行:SET GLOBAL binlog_expire_logs_seconds = 604800; - 为防冲突,顺手清掉旧参数:
SET GLOBAL expire_logs_days = 0; - 关键一步:编辑
/www/server/mysql/etc/my.cnf(宝塔路径,不是/etc/my.cnf),在[mysqld]段末尾添加两行:[mysqld] binlog_expire_logs_seconds = 604800 expire_logs_days = 0
- 保存后重启:
systemctl restart mysqld(或用宝塔面板点重启) - 重启后立刻验证:
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';,值必须是你设的秒数
手动 PURGE 前必须核对主从位置
配置生效后,已堆积的旧日志不会自动删,得手动触发一次 PURGE。但直接删会断主从——删掉从库还没读的日志,Slave_IO_Running 立刻变 No,报错 Got fatal error 1236。
- 主库上查当前写到哪:
SHOW MASTER STATUS;,记下File字段(如mysql-bin.000042) - 每台从库连上去执行:
SHOW SLAVE STATUS\G,重点看Relay_Master_Log_File和Exec_Master_Log_Pos - 找出所有从库中
Relay_Master_Log_File最旧的那个(比如mysql-bin.000035),这就是安全下限——你最多只能PURGE TO 'mysql-bin.000036';(删掉 000036 之前的所有) - 命令示例:
PURGE BINARY LOGS TO 'mysql-bin.000036';或PURGE BINARY LOGS BEFORE '2026-05-25 00:00:00';(注意时间格式必须是Y-m-d H:i:s)
清理后空间没释放?大概率是文件句柄没关
执行 PURGE 后 df -h 看磁盘没变化,不是命令失败,而是 MySQL 进程还拿着已删除文件的句柄。Linux 下这种“已删未释放”很常见。
- 验证方法:
lsof | grep 'deleted' | grep mysql,如果看到类似mysqld.* * 12u REG 253,1 1073741824 123456 /var/lib/mysql/mysql-bin.000030 (deleted),就坐实了 - 不用重启 MySQL:执行
FLUSH LOGS;即可强制 MySQL 关闭旧句柄、打开新 binlog,内核立刻回收空间 - 如果 MySQL 已卡死无法连接,才考虑重启;但务必确认主从状态再操作
最易被忽略的一点:max_binlog_size 默认是 1GB,高频写入下单个文件撑满后才切,容易导致某天突然多出一个巨无霸日志。建议调成 100M 或 250M,让清理更细粒度、更及时。











