purge binary logs 未生效主因是被复制线程占用或受 gtid_purged 保护;时间基准为服务器本地时间;expire_logs_days 非实时且不删当前活跃文件;执行前须确认从库无延迟、备份完整、无人正用 binlog 分析。

为什么 PURGE BINARY LOGS 执行后日志没删干净
常见现象是执行了 PURGE BINARY LOGS TO 'mysql-bin.000010' 或 PURGE BINARY LOGS BEFORE '2024-01-01 00:00:00',但磁盘空间没明显下降,SHOW BINARY LOGS 看到的文件数也没变少。
根本原因:MySQL 只会删除「不在任何复制线程使用中」且「不被 gtid_purged 覆盖」的 binlog 文件。如果从库(replica)还没读完某个 binlog,主库就无法清理它;或者启用了 GTID 且 gtid_purged 包含了较旧的事务范围,也会锁住对应 binlog。
- 用
SHOW REPLICA STATUS\G检查Relay_Master_Log_File,确认从库已追平到哪条 binlog - 用
SELECT @@gtid_purged;查看当前最小保留点,PURGE不会删掉它之前的文件 - 若从库延迟大,别硬 purge —— 先解决复制延迟,否则可能引发数据不一致
PURGE BINARY LOGS BEFORE 的时间基准到底以什么为准
这个时间是 MySQL 服务器本地系统时间(SELECT NOW();),不是 binlog 文件的 mtime,也不是事件写入时间戳。binlog 文件头里记录的是第一个事件的时间,但 BEFORE 判断依据是文件名末尾编号隐含的创建顺序 + log_bin_index 中记录的文件生成时间(由 mysqld 记录)。
- 执行前务必同步主从服务器时间(NTP),否则
BEFORE '2024-06-01'在时区/时间不准的机器上可能误删或漏删 - 不要依赖
ls -lt看文件修改时间 —— binlog 文件可能被 touch 过,或写入后未刷新元数据 - 推荐优先用
TO 'mysql-bin.000123'方式,更可控;BEFORE更适合定时脚本配合DATE_SUB(NOW(), INTERVAL 7 DAY)
自动清理配置 expire_logs_days 为什么有时不生效
这个参数只在 mysqld 启动时、以及每小时由后台线程扫描一次时触发清理,不是实时的。而且它只作用于「非活跃」的 binlog —— 正在写的那个当前文件(如 mysql-bin.000150)永远不会被自动删掉。
- 设置后需重启或执行
SET GLOBAL expire_logs_days = 7;,但注意:动态设置仅对后续新生成的 binlog 生效,已有旧文件仍需手动PURGE - MySQL 8.0.11+ 已弃用该变量,改用
binlog_expire_logs_seconds(单位秒),优先级更高 - 如果磁盘突然告警,别等自动清理 —— 立即人工
PURGE,并检查是否因max_binlog_size设置过大导致单个文件膨胀过快
执行 PURGE 前必须确认的三件事
这不是一个可以随便跑的命令。删错 binlog 可能导致从库中断、GTID 集不连续、甚至无法做基于时间点的恢复。
- 确认没有延迟大的从库:
SELECT * FROM performance_schema.replication_connection_status WHERE SERVICE_STATE = 'ON'; - 确认备份已包含 purge 范围之外的最新 binlog —— 即使有 xtrabackup,也要验证
binlog_info中的起始文件是否还在磁盘上 - 确认没人在用
mysqlbinlog --start-datetime做故障分析 —— purge 后那些时间范围将永远不可查
真正麻烦的不是命令怎么写,而是删之前得知道“谁还指着这条 log 活着”。











