最稳妥的MySQL备份方案是用mysqldump配合gzip压缩、crontab定时执行、rsync异地同步及条件清理。需规避root硬编码、时区与权限陷阱,使用~/.my.cnf存凭据(600权限),加--single-transaction等参数确保一致性,文件名含日期,crontab显式声明PATH并转义%号,rsync优先于scp,上传成功后再清理旧备份,并校验gzip完整性和SQL头部。

用 mysqldump 生成可压缩的 SQL 备份文件
直接调用 mysqldump 是最稳妥的逻辑起点,但必须避开权限和时区陷阱。不要用 root 用户硬编码在脚本里,改用配置文件方式加载凭据:~/.my.cnf(权限必须设为 600),内容如下:
[client] user = backup_user password = your_secure_password host = localhost
备份命令建议带 --single-transaction --routines --triggers --events,尤其对 InnoDB 表能避免锁表;加上 --set-gtid-purged=OFF 可防止 GTID 导致恢复失败。文件名务必含日期,例如:
mysqldump --all-databases | gzip > "/backup/mysql_$(date +\%Y\%m\%d_\%H\%M).sql.gz"
用 crontab 实现定时执行,但要注意环境变量缺失
crontab 默认不加载你的 shell profile,PATH 很可能不含 /usr/bin 或 /usr/local/bin,导致 mysqldump 找不到。要么在 crontab 条目开头显式声明 PATH:
PATH=/usr/local/bin:/usr/bin:/bin 0 2 * * * /bin/bash /home/backup/mysql_backup.sh
要么在脚本第一行用绝对路径调用命令,比如 /usr/bin/mysqldump。另外,crontab 中的 % 是特殊字符,必须转义,否则任务会静默失败。
上传到异地用 rsync 比 scp 更可靠
scp 传大文件容易断、无法续传;rsync 支持增量同步、断点续传、带宽限制,更适合备份场景。关键参数组合是:
-
-avz:归档+详细+压缩 -
--delete-after:删远端多余文件前先完成传输 -
--bwlimit=2000:限速 2MB/s,避免占满带宽 -
-e "ssh -p 2222":指定非标 SSH 端口(如有)
上传前建议先用 rsync --dry-run 测试路径和权限是否通。如果目标是对象存储(如 AWS S3、腾讯云 COS),就别硬刚 rsync,直接用官方 CLI 工具,比如 aws s3 cp 或 coscli upload,它们原生支持分块上传和失败重试。
清理本地旧备份要防误删,且得配合上传结果判断
不能无脑 find /backup -name "*.sql.gz" -mtime +7 -delete。必须等上传成功后再删,否则网络抖动导致上传失败,本地又清空,就彻底没备份了。推荐写成条件链式操作:
if rsync -avz --bwlimit=2000 /backup/mysql_*.sql.gz user@remote:/data/backup/; then find /backup -name "mysql_*.sql.gz" -mtime +7 -delete else echo "Upload failed, keep local files" | logger -t mysql-backup fi
日志用 logger 而不是写文件,避免磁盘写满影响 MySQL。另外,mtime 是按修改时间算的,而备份文件是刚生成的,所以它实际生效依赖你是否在 gzip 后再做一次 touch —— 更稳妥的做法是用 -name "mysql_$(date -d '7 days ago' +\%Y\%m\%d)*.sql.gz" 按文件名日期删。
异地备份真正难的不是命令拼写,而是上传失败后有没有通知、旧备份删没删错、以及恢复时发现 SQL 文件头部有乱码或截断——这些都得靠每次生成后加一句 gzip -t 和 head -n 1 校验。


















