binlog_expire_logs_seconds 并非失效,而是仅在 mysqld 启动、执行 flush logs 或 binlog 达 max_binlog_size 切换时触发清理;若长期无触发事件、被 lock instance for backup 阻塞或参数配置冲突(如 expire_logs_days 非零),则旧日志持续累积导致磁盘爆满。

binlog_expire_logs_seconds 不是失效了,而是没触发清理时机——它根本不是定时任务,只在特定事件发生时检查并删除过期文件。
清理只在三个时刻触发,不是每秒扫描
MySQL 8.0 的binlog_expire_logs_seconds 依赖外部事件驱动,而非后台定时轮询。如果长时间没触发,旧 binlog 就会越积越多,磁盘就爆了。
-
mysqld启动时会检查一次 - 执行
FLUSH BINARY LOGS或FLUSH LOGS时会检查 - 当前 binlog 文件写满
max_binlog_size、自动切换新文件时会检查
常见误判:设了 604800(7 天)就以为“7 天后自动删”,结果发现 10 天了文件还在。其实是因为当前 binlog 还没写满、也没手动 flush、服务也没重启,压根没走到清理逻辑。
LOCK INSTANCE FOR BACKUP 会阻塞清理
xtrabackup 等工具备份时默认加LOCK INSTANCE FOR BACKUP,这个锁会阻止 binlog 切换和自动 purge 流程。
- 锁持有期间,即使 binlog 写满了也不会切换新文件
- 即使你执行了
FLUSH BINARY LOGS,也可能被锁阻塞住,命令卡住不返回 - 解锁后,MySQL 不会“补做”被跳过的清理,得你手动再 flush 一次
所以备份完磁盘空间没释放?先确认是否锁还没释放,再执行一次 FLUSH BINARY LOGS。
参数冲突或未生效,查比猜靠谱
binlog_expire_logs_seconds 生效的前提是:
- 值必须是非零整数(如
604800),设为0= 永不清除 -
binlog_expire_logs_auto_purge必须为ON(默认是,但某些配置可能覆盖) - 不能同时设非零的
expire_logs_days,否则报错3683或静默忽略新参数
验证方式只有一条:
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';<br>SHOW VARIABLES LIKE 'binlog_expire_logs_auto_purge';两个都得有值、且符合预期。别信配置文件里写了就算数,MySQL 启动时可能因语法错误跳过某行。
PURGE 是唯一能立刻释放磁盘的操作
自动策略管的是“未来生成的日志生命周期”,对已存在的旧文件完全不管——哪怕你把binlog_expire_logs_seconds 从 30 天改成 1 小时,昨天生成的 binlog 也不会立刻过期。
要立刻腾空间,只能手动 PURGE:
- 先确认主从安全边界:查所有从库的
Relay_Master_Log_File,取最旧的那个文件名 - 再执行
PURGE BINARY LOGS TO 'mysql-bin.000123';(删掉该文件之前的所有) - 或用时间:
PURGE BINARY LOGS BEFORE '2026-06-25 00:00:00';(注意格式严格)
执行后 df -h 可能不立刻显示空间释放——Linux 文件句柄还被 mysqld 占着,用 lsof | grep deleted 能看到,通常重启 mysqld 或等下次 binlog 切换才会真正归还。
真正容易被忽略的点是:清理不是“设了就完事”,而是“设了 + 触发 + 安全删”三步缺一不可;而触发条件,恰恰藏在你日常运维动作(比如备份、flush、重启)里。











