真正能跑通的MySQL备份脚本核心是失败有反馈、成功可验证:需用set -e中断错误、校验文件非空、检查mysqldump退出码、时间戳精确到秒、禁用明文密码(改用权限600的~/.my.cnf)、crontab指定绝对路径并保留错误日志、清理备份优先按文件名日期而非mtime。

mysqldump 本身不支持自动调度,必须靠外部机制驱动;直接在脚本里写明文密码、忽略 --single-transaction、用 find -mtime 清理却没验证文件是否真正生成——这三类操作是线上备份脚本失效最常见的原因。
怎么写一个真正能跑通的备份脚本
核心不是“能导出”,而是“失败时有反馈、成功时可验证”。脚本要包含显式错误判断和基础校验:
- 用
set -e让任意命令失败立即退出,避免后续步骤静默执行 - 导出后立刻检查文件大小:
if [ ! -s "$BACKUP_FILE" ]; then echo "empty backup"; exit 1; fi - 压缩前先确认
mysqldump退出码为 0,再调用gzip - 文件名必须含完整时间戳(
%Y%m%d_%H%M%S),不能只用%F,否则同天多次运行会覆盖 - 不要用
root账号跑备份;创建专用用户并只给SELECT, LOCK TABLES权限
为什么必须用 ~/.my.cnf 而不是 -u/-p 参数
明文密码出现在 ps aux 或 shell 历史中,任何有权限查进程的人都能看到。而 ~/.my.cnf 是唯一被 mysqldump 官方支持的免密方式,且要求权限严格为 600:
- 配置内容必须是:
[client]段,不能写成[mysqldump](后者不生效) - 路径必须是执行用户的家目录下,比如
crontab以root运行,就得放/root/.my.cnf - 脚本里直接调用
mysqldump --defaults-extra-file=/root/.my.cnf ...更稳妥,避免环境变量干扰
crontab 定时任务总不触发?先看这三点
90% 的“定时没执行”问题出在环境差异,不是语法错:
-
crontab -e编辑的是当前用户的定时任务,但备份脚本常需root权限访问数据库和写入系统路径,务必用sudo crontab -e - crontab 默认
$PATH极简(通常只有/usr/bin:/bin),mysqldump若装在/usr/local/mysql/bin,必须写绝对路径,或在脚本开头加export PATH="/usr/local/mysql/bin:$PATH" - 重定向输出别全丢进
/dev/null;至少保留错误日志:0 2 * * * /opt/scripts/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
find -mtime +7 清理备份很危险?
它按文件「修改时间」删,不是按文件名里的日期。如果某次备份因磁盘满失败,留下一个空文件,-mtime 仍会把它当“旧文件”放过;而真正该删的、上周成功生成的备份,可能因后续 touch 操作被误删。
更可靠的做法是解析文件名中的日期:
find "$BACKUP_DIR" -name "*.sql.gz" -print0 | while IFS= read -r -d '' file; do
filename=$(basename "$file")
date_part=$(echo "$filename" | grep -oE '[0-9]{8}_[0-9]{6}')
if [[ $date_part ]] && [[ $(date -d "$date_part" +%s 2>/dev/null) -lt $(date -d "7 days ago" +%s) ]]; then
rm -f "$file"
fi
done不过对中小规模部署,find -mtime +7 仍够用——前提是脚本每次失败都彻底中断,不留下半截文件。
真正难的不是让脚本跑起来,而是让它在磁盘告警、MySQL临时不可达、cron服务重启后,依然能自愈或明确报错。备份脚本不该是个“设完就忘”的黑盒。


















