logrotate 配置必须严格匹配 mysql 实际 slow_query_log_file 绝对路径,确保父目录存在且属主为 mysql:mysql;postrotate 中需用 set global slow_query_log = off/on 重载日志句柄,并配置 create 640 mysql mysql 保证权限正确。

logrotate 配置文件必须匹配 slow_query_log_file 路径
logrotate 不会自动发现 MySQL 的慢日志路径,它只按你写的绝对路径轮转。如果 slow_query_log_file 设为 /var/log/mysql/slow.log,但 logrotate 配置里写的是 /var/lib/mysql/hostname-slow.log,那就完全不生效——日志照常涨满磁盘,而你还在查 logrotate 是否运行成功。
确认当前真实路径的最可靠方式是登录 MySQL 执行:
SELECT @@slow_query_log_file;
拿到结果后,直接复制粘贴进 logrotate 配置,不要手敲、不要猜、不要用 hostname 命令拼接。
- 路径中若含变量(如
$HOSTNAME)或符号链接,logrotate 无法解析,必须用最终解析后的绝对路径 - 路径父目录(如
/var/log/mysql/)必须存在,且属主属组为mysql:mysql - 若 MySQL 是容器化部署,确保该路径在宿主机上可挂载、可写入
postrotate 脚本必须重载 slow_query_log 开关
MySQL 不会自己“感知”日志文件被轮转了。logrotate 把旧日志改名、创建新空文件后,MySQL 还在往原 fd 写——也就是继续往已重命名的旧文件里追加,导致新日志永远为空。
解决办法是在 postrotate 段调用 MySQL 命令,强制刷新日志句柄:
postrotate mysql -u root -p'your_pass' -e "SET GLOBAL slow_query_log = OFF; SET GLOBAL slow_query_log = ON;" endscript
- 密码不能裸写在命令行(有泄露风险),建议用
~/.my.cnf配置免密登录,或用--defaults-extra-file指定配置文件 -
SET GLOBAL slow_query_log = OFF/ON是唯一安全有效的重载方式;FLUSH LOGS不影响 slow log 句柄 - 云数据库(如阿里云 RDS、腾讯云 CDB)通常禁用
SET GLOBAL,此时只能靠 DBA 或平台控制台手动触发日志 reopen
rotate 参数和 compress 要配合业务日志量调整
默认 rotate 30 + daily 看似合理,但对高并发业务可能迅速耗尽磁盘:一条慢查询日志平均 200–500 字节,每秒 10 条就是每天 86MB;若没开 compress,30 天就占 2.5GB;若开了但没设 dateext,旧日志会被覆盖,丢失关键时间窗口数据。
- 先观察一周日志体积:
du -sh /var/log/mysql/slow.log*,再决定保留天数 - 务必启用
dateext和dateformat -%Y%m%d,避免轮转冲突和时间混乱 - 若日志量极大(如 >100MB/天),考虑临时调低
long_query_time或关闭log_queries_not_using_indexes,而不是盲目增加保留数
权限问题最容易静默失败
logrotate 以 root 身份运行,但新建日志文件的属主必须是 MySQL 进程用户(通常是 mysql),否则 MySQL 启动或重载后无法写入,且不会报错——日志停止增长,你却查不到任何错误提示。
关键配置项是 create 640 mysql mysql,它表示:
- 轮转后新建的
slow.log文件权限为640 - 所有者是用户
mysql,所属组也是mysql - 若实际 MySQL 用户是
mysqld或root(极少见),这里必须同步改掉
验证方式:手动执行一次 logrotate 测试(sudo logrotate -d /etc/logrotate.d/mysql-slow 查调试输出),然后 ls -l /var/log/mysql/slow.log 确认属主和权限是否符合预期。
真正难排查的不是配置写错,而是路径权限、用户属主、MySQL 进程身份三者没对齐——它们之间差一个字符,日志就停更,而 MySQL 自己连个 warning 都不吐。











