mysql 8.0.11+ 应使用 binlog_expire_logs_seconds(如604800秒)替代已废弃的 expire_logs_days;该参数需写入 my.cnf 的 [mysqld] 段并重启生效,或 set global 动态设置(重启丢失),清理仅在启动或 flush logs 时触发,不实时轮询,且不删当前活跃日志。

直接设 expire_logs_days 或 binlog_expire_logs_seconds 是最稳的解法,但必须写进配置文件才不会重启失效;磁盘已满时得先用 PURGE BINARY LOGS 手动删,不能直接 rm 文件。
为什么改了 expire_logs_days 还不自动删日志
这个参数只在 MySQL 启动时或执行 FLUSH LOGS 时触发清理逻辑,不是实时轮询。它也不会删当前正在写的 binlog(比如 mysql-bin.000156),只清理旧的、已归档的文件。
- 临时生效用:
SET GLOBAL expire_logs_days = 7;,但 MySQL 重启后就丢 - 永久生效必须加到
/www/server/mysql/etc/my.cnf的[mysqld]段里,再重启服务 - MySQL 8.0.11+ 该参数已被标记为 deprecated,建议改用
binlog_expire_logs_seconds = 604800(7 天) - 设为 0 表示永不过期,等同于没开自动清理
磁盘 100% 占用时怎么紧急释放空间
MySQL 进程还在跑,但 df -h 显示磁盘已满,这时不能删文件系统里的 mysql-bin.*,否则可能损坏主从同步甚至导致 MySQL 崩溃。
- 先登录 MySQL:
mysql -u root -p - 查当前有哪些日志:
SHOW BINARY LOGS;,注意最老的那条(比如mysql-bin.000098)是否还被从库依赖(SHOW SLAVE STATUS\G中看Relay_Master_Log_File) - 安全起见,按文件名删:
PURGE BINARY LOGS TO 'mysql-bin.000123';(保留 123 及之后的) - 如果确定从库已追上,也可以按时间删:
PURGE BINARY LOGS BEFORE '2026-04-10 00:00:00'; - 删完发现
df -h空间没变?执行lsof | grep deleted,大概率是 MySQL 还拿着已删文件的句柄,此时重启 MySQL 或手动执行FLUSH BINARY LOGS才能真正回收
max_binlog_size 能缓解暴涨,但不能替代过期策略
这个参数控制单个 binlog 文件最大体积(默认 1GB),达到后会自动切新文件。它不减少总日志量,只是让文件更碎、更易管理。
- 设太小(如 100M)会导致频繁切换,增加索引文件(
mysql-bin.index)写入压力 - 设太大(如 2G)虽减少切换次数,但单次
PURGE或备份时 I/O 更集中 - 和
expire_logs_days配合用才合理:前者控单文件大小,后者控总保留时长 - 修改需加到
my.cnf并重启,不支持动态 SET
别踩这些坑
很多问题其实出在“以为删了就完了”,但主从架构下 binlog 是链式依赖的。
- 不要在主从环境里执行
RESET MASTER,它会清空所有 binlog 并重置序列号,从库立刻报错Got fatal error 1236 - 删日志前不看
SHOW SLAVE STATUS\G,容易把从库还没读的mysql-bin.000001给删了 - 在宝塔面板里改完
my.cnf忘了点「重启 MySQL」,参数压根没加载 - MySQL 8.0+ 还硬写
expire_logs_days,虽然兼容但会被 warn,且未来版本可能彻底移除
真正麻烦的从来不是删日志,而是删错日志——尤其是主从延迟高、又没定期检查 Relay_Master_Log_File 的时候。参数调完别忘了验证:SHOW VARIABLES LIKE 'binlog_expire_logs_seconds'; 和 SHOW BINARY LOGS; 多跑两遍。











