mysqldump 配合 crontab 是最轻量可控的 mysql 自动化备份方案,关键在于脚本健壮性、合理时间策略及规避权限与路径问题;必须加 --single-transaction 和 --routines 等参数保障一致性与完整性。

mysqldump 配合 crontab 是最轻量、最可控的 MySQL 自动化备份方案,不需要额外服务或 GUI 工具,关键在于脚本健壮性 + 时间策略合理 + 权限与路径不踩坑。
备份命令必须加 --single-transaction 和 --routines
不加这些参数,备份可能在事务中途截断,或漏掉存储过程、函数、事件。尤其当数据库有写入时,mysqldump 默认不保证一致性。
常见错误现象:mysqldump: Got error: 1146: Table 'xxx' doesn't exist(表被删/重命名中);或还原后触发器没生效。
-
--single-transaction:对 InnoDB 表开启一致性快照,避免锁表,适合线上库 -
--routines:导出存储过程和函数;--events要加才导出事件调度器 -
--triggers默认开启,但显式写上更稳妥 - 别用
-p密码直接拼写——明文密码会留在ps aux和 bash 历史里,改用配置文件或环境变量
Shell 脚本要处理好路径、权限和失败退出
很多脚本本地能跑,一丢进 crontab 就失败,核心原因是 cron 环境变量缺失、PATH 不同、当前目录不确定。
实操建议:
- 脚本开头固定写
#!/bin/bash,并用绝对路径调用mysqldump(如/usr/bin/mysqldump或/usr/local/mysql/bin/mysqldump) - 所有路径用绝对路径,比如备份目录写成
/backup/mysql,别用~/backup或./backup - 加上
set -e,让任意命令失败时脚本立即退出,避免后续步骤误执行 - 用
mysql -u... -e "SELECT 1"先探测连接是否正常,失败就直接 exit,不继续 dump - 压缩用
gzip比tar更省事,mysqldump ... | gzip > file.sql.gz一行搞定,少一个临时文件
crontab 时间表达式容易写错,优先用 @daily 或明确时间点
新手常把 0 2 * * * 写成 2 0 * * *(后者是每天凌晨 0 点 2 分),或者忽略系统时区导致备份时间偏移。
推荐写法:
-
@daily:等价于0 0 * * *,语义清晰,cron 守护进程自动处理时区 - 如果必须指定小时分钟,统一用 UTC 或确认服务器
timedatectl status输出的时区(比如CST≠ 中国标准时间,可能是美国中部) - 加日志重定向:
0 2 * * * /backup/scripts/backup_mysql.sh >> /backup/logs/backup.log 2>&1,否则 cron 失败无声无息 - 测试时先设成每 5 分钟一次(
*/5 * * * *),验证脚本能跑通再切回正式周期
保留 N 个备份不能只靠 ls | head -1,得用 find -mtime 或按文件名排序
原始脚本里用 ls -crt | head -1 找最早文件,看似合理,但 ls -c 按“状态变更时间”排序,不是“创建时间”,而 ext4 文件系统不存创建时间,备份文件的 ctime 可能因 chmod、chown 等操作被意外更新,导致删错文件。
更稳的做法:
- 文件名强制带日期,如
mydb_$(date +\%Y\%m\%d_\%H\%M\%S).sql.gz - 用
find /backup/mysql -name "mydb_*.sql.gz" -mtime +7 -delete删除 7 天前的 - 或按文件名排序删旧:
ls -r mydb_*.sql.gz | tail -n +8 | xargs rm -f(保留最新 7 个) - 删除前加
echo预览,确认无误再真正rm
备份路径本身最好挂载在独立磁盘分区,避免备份撑爆系统盘导致 MySQL 进程异常退出——这个点常被忽略,但比脚本逻辑出错后果更严重。











