expire_logs_days设了不生效是因为MySQL只在日志切换时清理过期binlog,而非定时轮询;低流量下binlog不滚动则不会触发清理,需执行FLUSH LOGS或改用binlog_expire_logs_seconds。

为什么 expire_logs_days 设了不生效?
常见现象是:明明在 my.cnf 里写了 expire_logs_days = 7,重启 MySQL 后查 SHOW VARIABLES LIKE 'expire_logs_days'; 也显示 7,但几天后 ls -lh /var/lib/mysql/*.bin 发现老 binlog 还在。
根本原因是:MySQL 只在「日志切换时」检查并清理过期 binlog,而不是定时轮询。如果业务写入极少、主库长期没产生新事务,binlog 文件就不会滚动,旧文件也就不会被触发删除。
- 确认是否发生日志切换:执行
FLUSH LOGS;(会生成新 binlog),再等几秒,观察旧文件是否消失 -
expire_logs_days是基于文件**最后修改时间**判断过期,不是创建时间;若手动 touch 过文件,可能误判 - MySQL 8.0.11+ 默认启用
binlog_expire_logs_seconds(优先级高于expire_logs_days),设了它就会忽略后者
手动清理前必须检查的三件事
直接 PURGE BINLOGS 很快,但删错会导致从库同步中断或无法恢复数据。务必先确认:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 所有从库的
SHOW SLAVE STATUS\G中Relay_Master_Log_File值,不能比你要删的最老 binlog 更新——否则从库会报Could not find first log file name in binary log index file - 用
SHOW MASTER LOGS;查看当前最新 binlog 文件名,确保你 PURGE 的范围不包含它(比如当前是mysql-bin.000123,就别 PURGE 到mysql-bin.000123) - 如果启用了 GTID(
gtid_mode = ON),不能按文件名 PURGE,得用PURGE BINLOGS TO 'xxx' OR BEFORE 'yyyy-mm-dd hh:mm:ss',否则可能删掉从库还没消费的事务
PURGE BINLOGS 的两种安全用法
线上环境推荐用时间点方式,比按文件名更可控;但要注意 MySQL 服务器时间与业务日志时间是否一致。
- 按时间清理(推荐):
PURGE BINLOGS BEFORE '2024-05-01 00:00:00';—— 删除该时间点之前的所有 binlog - 按文件名清理(需谨慎):
PURGE BINLOGS TO 'mysql-bin.000100';—— 删除 所有编号小于mysql-bin.000100的文件(注意不是“到”这个文件为止) - 执行后立即生效,不可回滚;建议先在测试库跑一遍,观察从库是否异常
MySQL 8.0+ 推荐用 binlog_expire_logs_seconds
这个变量精度更高(秒级),且和系统时钟解耦(基于 binlog 写入时间戳),比天数更准。但要注意兼容性:
- 设为 604800(7 天):
SET PERSIST binlog_expire_logs_seconds = 604800;(持久化到选项文件) - 如果已设
expire_logs_days,必须先SET PERSIST expire_logs_days = 0;,否则后者会覆盖前者 - 某些云厂商 RDS(如阿里云 PolarDB)禁用
SET PERSIST,只能改参数模板再重启
真正容易被忽略的是:清理动作依赖日志切换,而低流量实例可能一周都不切一次。所以别只靠自动策略,定期人工检查 SHOW MASTER LOGS; 和磁盘使用率才是底线。

















