MySQL 8.0错误日志不支持原生按天轮转,需用FLUSH ERROR LOGS(≥8.0.30)配合定时脚本实现:检查实例存活、验证文件占用、安全切日志、归档清理旧文件并校验新日志有效性。

MySQL 8.0不支持直接按天轮转错误日志
MySQL 自身的 error_log(错误日志)在 8.0 中默认是单文件、不支持 log_rotation 或时间粒度切分。即使启用 log_error_verbosity 或配置 log_error 路径,它也不会自动创建 mysqld.err.20240515 这类文件——这点和 slow log 或 general log 不同,后者可通过 FLUSH SLOW LOGS 等触发重命名,但错误日志没有对应命令。
必须用 Shell 脚本 + FLUSH ERROR LOGS 配合外部轮转
MySQL 8.0.30+ 才引入 FLUSH ERROR LOGS(早期 8.0.x 版本不支持),它的作用是:关闭当前错误日志文件句柄,并以 log_error 配置路径为基准,追加当前时间戳(格式为 YYYY-MM-DD-HH-MM-SS)生成新文件。但注意:它不是“按天”,而是“每次执行都切一次”,所以需配合定时任务控制频率。
- 确认 MySQL 版本 ≥ 8.0.30:
SELECT VERSION(); - 检查是否启用该命令:
FLUSH ERROR LOGS;若报错Unknown command,说明版本太低或未编译支持 -
log_error必须是绝对路径(如/var/log/mysql/error.log),不能是相对路径或stderr - 执行后原文件不会被删除或重命名,而是新建一个带时间戳的文件;旧文件仍存在,需脚本手动归档或清理
Shell 脚本要点:避免并发冲突与权限问题
直接 crontab 每天跑 mysql -e "FLUSH ERROR LOGS;" 很危险:若 MySQL 正在写日志、脚本又没做锁判断,可能造成日志丢失或句柄混乱。实际脚本要包含:
- 用
mysqladmin ping检查实例存活,失败则退出,不硬执行 - 用
fuser -v /var/log/mysql/error.log 2>/dev/null检查文件是否正被 mysqld 占用(应有 mysqld 进程在用),避免误操作 - 使用
--defaults-file指定配置文件读取账号密码,不把密码写进命令行或~/.my.cnf(防止泄露) - 切完后用
find /var/log/mysql -name "error.log.*" -mtime +7 -delete清理 7 天前的归档日志 - 日志切割动作本身记入系统日志:
logger -t mysql-rotate "flushed error logs at $(date)"
crontab 示例与关键陷阱
不要设成 0 0 * * * /path/to/rotate.sh —— 如果 MySQL 恰好在凌晨 0 点重启,FLUSH ERROR LOGS 可能失败且无提示。更稳妥的是:
30 1 * * * /bin/bash /opt/mysql/scripts/flush-error-logs.sh >> /var/log/mysql/rotate.log 2>&1
- 选凌晨 1:30 是避开多数备份/维护窗口,也给 MySQL 留出启动稳定时间
- 必须重定向输出,否则 cron 默认邮件告警会堆积(尤其失败时)
- 脚本内所有 mysql 命令都要加超时:
timeout 10s mysql --defaults-file=/etc/mysql/debian.cnf -e "FLUSH ERROR LOGS;" - MySQL 用户需有
RELOAD权限(通常 root 或 debian-sys-maint 有),普通账号执行会报Access denied; you need (at least one of) the RELOAD privilege(s)
真正难的不是写脚本,而是让 FLUSH ERROR LOGS 在各种异常场景下(主从切换中、崩溃恢复后、日志路径变更后)依然安全触发——这需要每轮执行后校验新日志文件 mtime 和非空大小,缺一不可。


















