正确做法是用 logrotate 配合 FLUSH LOGS:配置 postrotate 脚本执行 mysql -S /var/run/mysqld/mysqld.sock -e "FLUSH LOGS",确保日志文件被 MySQL 重新打开,避免直接删除导致磁盘空间不释放。

MySQL 的 slow_query_log 或 error_log 膨胀太快,直接删文件会丢日志
MySQL 自身不管理日志文件生命周期,slow_query_log_file 和 log_error 指向的文件会一直追加,直到磁盘写满。直接 rm 或 mv 正在写的日志文件,MySQL 进程仍持有文件句柄,磁盘空间不会释放——这是最常踩的坑。
正确做法是交由 logrotate 管理,并配合 MySQL 的日志刷新机制:
- 配置
logrotate用copytruncate(安全但有极小丢失风险),或更推荐的postrotate脚本 +FLUSH LOGS -
FLUSH LOGS会让 MySQL 关闭当前日志文件、重新打开同名新文件(需确保权限一致) - 确保
logrotate执行用户(通常是root)能连上 MySQL 执行命令,或用免密 socket 认证
logrotate 配置里必须写 postrotate 而不是只靠 copytruncate
copytruncate 看似简单:复制内容后清空原文件。但它在高并发写入时可能丢几行日志,且无法保证 MySQL 文件指针同步。生产环境应优先走 postrotate + FLUSH LOGS 流程。
示例配置片段(/etc/logrotate.d/mysql):
/var/log/mysql/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 640 mysql adm
sharedscripts
postrotate
if [ -f /var/run/mysqld/mysqld.pid ]; then
mysql -S /var/run/mysqld/mysqld.sock -e "FLUSH LOGS;" >/dev/null 2>&1 || true
fi
endscript
}
-
sharedscripts确保多个日志文件共用一套postrotate,避免重复执行FLUSH LOGS -
mysql -S ... -e "FLUSH LOGS"必须用 socket 连接(比 TCP 更可靠),且路径要和 MySQL 实际socket一致(查mysqld --verbose --help | grep socket) -
|| true防止logrotate因 MySQL 临时不可用而中断轮转
MySQL 日志路径权限不对,logrotate 会静默失败
logrotate 默认以 root 身份运行,但 MySQL 进程(mysql 用户)需要能继续往新日志文件写入。如果 create 指定的权限或属组不对,下次启动或 FLUSH LOGS 后会报错:Can't open log file 或写入失败。
-
create 640 mysql adm中的mysql是属主,adm是属组(Debian/Ubuntu 常见;CentOS 可能是mysql组) - 确认 MySQL 配置中
log_error和slow_query_log_file路径的父目录(如/var/log/mysql/)对mysql用户可写:ls -ld /var/log/mysql - 若用 SELinux(RHEL/CentOS),需确保上下文正确:
restorecon -Rv /var/log/mysql
误配 logrotate 导致慢查询日志被轮转但没生效
常见现象:配置改了,logrotate -d /etc/logrotate.d/mysql 显示“rotating log”,但第二天发现 slow_query_log_file 还是旧文件、大小没变。大概率是 MySQL 没真正收到 FLUSH LOGS,或日志路径没对上。
- 检查 MySQL 实际日志路径:
mysql -e "SELECT @@global.slow_query_log_file, @@global.log_error;",和logrotate配置里的路径必须完全一致(包括软链接展开后的真路径) -
logrotate -d是调试模式,不真正执行轮转;验证要用logrotate -f /etc/logrotate.d/mysql强制跑一次 - 观察 MySQL 错误日志是否有
Got signal 15或Received SIGUSR1(某些版本用信号触发日志切换),但主流还是依赖FLUSH LOGS
最麻烦的是日志路径带变量或符号链接——logrotate 看到的是路径字符串,MySQL 看到的是打开后的文件描述符,两者脱节就轮不起来。盯住 ls -l 输出和 lsof -p $(cat /var/run/mysqld/mysqld.pid) | grep log 结果,比猜配置管用。


















