MySQL binlog自动清理需设expire_logs_days(5.7)或binlog_expire_logs_seconds(8.0+),并配合FLUSH BINARY LOGS触发,非实时守护进程;未触发日志切换则不清理,且主从延迟或文件句柄占用会导致空间不释放。

MySQL安装后自动创建大量 binlog 文件,根本不是“安装导致”,而是因为 log_bin 默认开启(只要配置文件里有 log-bin 或启动时加了该选项),且 expire_logs_days 或 binlog_expire_logs_seconds 为 0 —— 意味着日志永不自动删除。
为什么设了过期参数却没删 binlog?
自动清理不是常驻守护进程,它只在两个时机触发:MySQL 启动时、或发生 binlog 切换(FLUSH BINARY LOGS 或当前文件大小 ≥ max_binlog_size)。如果业务写入极低,单个 mysql-bin.000xxx 几天都写不满 1GB,默认的 1GB 限值就卡住切换,清理逻辑根本不会跑。
- 检查是否真触发过切换:
SHOW BINARY LOGS;看文件数量是否随时间增长;不增长说明没切换,也就没清理机会 - 手动触发一次:
FLUSH BINARY LOGS;,之后立刻查SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';和SHOW BINARY LOGS;,看最早文件是否被删 - MySQL 5.7 中
expire_logs_days生效需重启 + 至少一次FLUSH LOGS;8.0+ 中若只设了expire_logs_days而没设binlog_expire_logs_seconds,该参数被忽略
MySQL 5.7 和 8.0+ 的过期参数不能混用
写错参数名或版本错配,等于白配。8.0.11+ 已废弃 expire_logs_days,即使你写了它,只要 binlog_expire_logs_seconds 存在(哪怕值为 0),旧参数就完全失效。
- 5.7 及更早:只认
expire_logs_days = 7,加进/www/server/mysql/etc/my.cnf的[mysqld]段并重启 - 8.0.11+(含宝塔常见 8.0.33):必须用
binlog_expire_logs_seconds = 604800(7 天),同时显式设expire_logs_days = 0避免歧义 - 路径别写错:宝塔用户配置文件通常在
/www/server/mysql/etc/my.cnf,不是/etc/my.cnf - 改完必须重启:
systemctl restart mysqld,否则 SET GLOBAL 的临时设置重启即丢
PURGE BINARY LOGS 手动清理后磁盘空间没释放?
执行 PURGE BINARY LOGS BEFORE '2026-06-01' 后 df -h 看不到空间回来,大概率是 MySQL 进程还拿着已删文件的句柄——常见于 xtrabackup 备份后未释放锁,或从库 IO 线程异常挂起。
- 验证方式:
lsof -nP | grep '/www/server/mysql/data/mysql-bin' | grep deleted,若有输出说明句柄被占 - 临时解法:重启 MySQL(
systemctl restart mysqld),但要注意主从延迟风险 - 注意:PURGE 不是“清空文件”,而是 unlink 文件 inode;空间真正回收依赖内核释放句柄,不是命令执行完就立刻见效
最易被忽略的一点:GTID 模式下禁止用 PURGE BINARY LOGS TO 'mysql-bin.000123',必须用时间点语法,否则会报错中断复制。而 SHOW SLAVE STATUS\G 里的 Relay_Master_Log_File 是唯一可信的安全边界,不是靠猜或看日期。


















