mysqldump 配合 cron 是 Debian 上最轻量可控的 MySQL 自动备份起点,但需规避权限、时间格式、密码泄露、环境变量、校验缺失等常见失效点,否则第二天即失败。

mysqldump 配合 cron 是 Debian 上最轻量、最可控的 MySQL 自动备份起点,但直接照搬网上脚本大概率会在第 2 天就失败——不是权限问题,就是备份文件打不开,或者恢复时发现全是空的。
为什么 mysqldump 脚本常在第二天失效
常见错误现象:mysqldump: Got error: 1045: Access denied for user 'xxx'@'localhost';或备份文件只有几 KB,head -n5 backup.sql 显示是错误提示而非 SQL;更隐蔽的是:脚本里用 -p$password(无空格)导致密码被当作参数名解析,MySQL 实际没认证就退出了。
- 必须用
-p"$db_password"或更安全地改用配置文件方式(见下条) -
date + "%y%m%d%h%m%s"是错的:%h是英文月份缩写(如 Jun),%H才是小时;%s是秒级时间戳,但和%m(分钟)混用会导致格式冲突 - 脚本未设置
umask 0077,生成的 .sql 文件权限为 644,任何本地用户都能读取密码明文(如果导出含CREATE USER语句) - 没检查
mysqldump是否真的成功:只靠$?不够,要加grep -q "^-- MySQL dump" "$backup_file"确认头部有效
用 ~/.my.cnf 避免密码硬编码与解析错误
把凭证从脚本里抽出来,既解决 -p 参数解析陷阱,又避免日志/ps 命令泄露密码。创建 /root/.my.cnf:
[client] user = backup_user password = your_strong_password host = localhost
然后立刻执行:chmod 600 /root/.my.cnf。之后脚本里只需写 mysqldump --databases myapp | gzip > $backup_file,完全不用提用户名密码。
- 这个配置文件仅对
mysql、mysqldump等客户端生效,不影响 MySQL 服务本身 - 不要放在
/etc/my.cnf—— 那里全局生效,可能干扰其他服务 - 如果用非 root 用户跑备份(比如
mysql用户),就把.my.cnf放它家目录并chown mysql:mysql,同时cron也得用该用户启
crontab 时间表达式与实际执行权限不匹配
你写 0 2 * * * /usr/local/bin/mysql_backup.sh,但 cron 默认 PATH 很窄,找不到 mysqldump 或 date;且环境变量(如 HOME)和交互式 shell 不同,.my.cnf 可能根本没被读到。
- 在 crontab 里显式声明环境:
PATH=/usr/local/bin:/usr/bin:/bin HOME=/root - 用绝对路径调用命令:
/usr/bin/mysqldump、/bin/date - 测试是否读到
.my.cnf:在脚本开头加mysql -e "SELECT 1" >/dev/null && echo "config OK" || echo "config FAIL" - 别依赖
sudo—— cron 不会给你 tty,sudo会卡住;所有权限应在 cron 用户自身搞定
保留与清理必须带校验,不能只看文件日期
find /var/backups/mysql -name "*.sql.gz" -mtime +7 -delete 看似合理,但若某次备份因磁盘满失败,只生成一个 0 字节的 .gz 文件,它也会活过 7 天,下次恢复时才发现是废的。
- 清理前先校验:
gzip -t "$file" && [ $(stat -c "%s" "$file") -gt 1024 ](至少 1KB) - 保留逻辑按「可用性」而非「时间」:例如始终留最近 3 个成功备份,而不是固定 7 天
- 远程同步失败时,本地备份也不该删 ——
rsync加--ignore-errors不保险,应单独判断$?并发告警
真正容易被忽略的点是:备份脚本里没设 set -e,某个 cd 失败后后续命令仍在执行,结果备份到了根目录或临时目录;还有就是没配 log-bin,导致哪怕备份完好,也无法做任意时间点恢复。


















