mysql日志轮转必须通过logrotate配合kill -usr1信号或flush logs命令实现,否则日志持续写入旧文件导致磁盘爆满;需先确认log_error和slow_query_log_file路径及启用状态,确保目录权限正确、pid路径准确、配置含sharedscripts,且严禁对binlog使用logrotate。

MySQL 错误日志和慢查询日志不会自动轮转,必须靠 logrotate 配合 MySQL 进程信号或命令触发文件切换;配错会导致日志继续写入旧文件、磁盘爆满、归档失效。
确认日志路径和启用状态
别急着写配置,先看 MySQL 实际在往哪写、写了哪些日志:
- 运行
mysql -u root -p -e "SHOW VARIABLES LIKE 'log_error';"和mysql -u root -p -e "SHOW VARIABLES LIKE 'slow_query_log_file';" - 如果
slow_query_log是OFF,slow_query_log_file配置再对也没用——得先在[mysqld]段加slow_query_log = ON并重启,或执行SET GLOBAL slow_query_log = ON;(注意部分变量需重启才生效) - 检查路径是否真实存在、权限是否正确:
ls -l /var/log/mysql/应显示属主是mysql:mysql;否则chown mysql:mysql /var/log/mysql,并确保目录可写
/etc/logrotate.d/mysql 配置必须带 sharedscripts 和 USR1
常见错误是轮转后 MySQL 还往旧文件里写,根本原因是进程没刷新文件句柄。关键不是“移动文件”,而是让 mysqld 关闭旧 fd、打开新文件:
-
sharedscripts必须加:否则多个日志路径会各自触发一次postrotate,而kill -USR1只需发一次 - 用
kill -USR1,不是SIGHUP或mysqladmin flush-logs:USR1是 MySQL 官方文档明确用于 reopen error/slow log 的信号;后者虽也能刷日志,但依赖 MySQL 客户端且可能因密码或权限失败 - PID 文件路径要对:
/var/run/mysqld/mysqld.pid是常见路径,但ps aux | grep mysqld才是唯一真相;若实际是/run/mysqld.pid,脚本就静默失效 - 避免通配符如
/var/log/mysql/*.log:万一目录里混了其他服务日志(比如backup.log),会被一并轮转甚至删掉
binlog 不能走 logrotate,必须交由 MySQL 自控
直接删 mysql-bin.000001 或用 logrotate 清理 binlog,会导致 mysql-bin.index 不一致、主从断裂、恢复失败。这是硬性边界,踩了就出事:
- 正确做法是在
[mysqld]中配置:expire_logs_days = 7(MySQL 5.7–8.0)或binlog_expire_logs_seconds = 604800(MySQL 8.0+) -
max_binlog_size = 100M控制单个文件大小,防止单文件过大 - 清理时用
PURGE BINARY LOGS BEFORE '2026-06-26 00:00:00';或PURGE BINARY LOGS TO 'mysql-bin.000010';
测试必须手动跑一次,不能只靠 cron
配置完不验证,等于没配。两个命令缺一不可:
-
sudo logrotate -d /etc/logrotate.d/mysql:看调试输出里有没有 “rotating pattern”、“running postrotate script”、“killing process” 等关键词 -
sudo logrotate -f /etc/logrotate.d/mysql:强制执行一次,然后检查ls -l /var/log/mysql/是否生成新日志、旧日志是否被压缩、tail -f新文件是否有实时写入
最容易被忽略的是 PID 路径和 sharedscripts —— 两者任一错,postrotate 就静默失败,日志照旧写进旧文件,表面看一切正常,实则轮转完全没生效。











