mysqldump 备份必须加 --single-transaction(innodb)或 --lock-all-tables(myisam),配合 --routines、--triggers、--events、--set-gtid-purged=off、--default-character-set=utf8mb4、--hex-blob,并通过权限为600的~/.my.cnf安全传参,脚本需校验退出码、文件大小及时间戳命名,crontab中显式设置path和绝对路径。

mysqldump 命令必须带 --single-transaction 才算真正可用
不加这个参数,InnoDB 表在备份过程中遇到并发写入,导出的数据可能跨事务不一致——比如用户信息更新了,但关联的订单明细没同步进去,恢复后业务逻辑就断了。--single-transaction会开启一致性快照,全程不锁表(仅对 InnoDB 有效)。
如果你的库混用 MyISAM(老系统常见),得先查引擎:SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db';;MyISAM 必须配合 --lock-all-tables,否则备份不可靠。
- 务必顺手加上
--routines、--triggers、--events,否则存储过程、触发器、事件全丢 - MySQL 5.7.6+ 默认开启 GTID,备份时得显式加
--set-gtid-purged=OFF,否则恢复时报错ERROR 1840 (HY000) - 字符集别乱:加
--default-character-set=utf8mb4防中文乱码,--hex-blob安全处理 BLOB 字段
密码绝不能出现在脚本里,~/.my.cnf 权限必须是 600
明文密码写进命令行,ps aux 一眼就能看到;存在脚本里,git 提交或日志轮转都可能泄露。唯一安全方式是用 MySQL 官方支持的配置文件:~/.my.cnf,且权限必须为 600(chmod 600 ~/.my.cnf)。
内容格式必须是:
[client] user=root password=your_real_password注意是
[client] 段,不是 [mysqldump](后者不生效);路径必须是执行用户的家目录——如果 crontab 以 root 运行,就得放 /root/.my.cnf。
- 脚本里调用时显式指定路径更稳妥:
mysqldump --defaults-extra-file=/root/.my.cnf --single-transaction your_db - 测试是否生效:用
sudo -u root /bin/bash -c 'mysqldump --defaults-extra-file=/root/.my.cnf -e "SELECT 1"'模拟 cron 环境
crontab 脚本总不执行?先检查 PATH 和工作目录
手动运行脚本成功,放进 crontab 就静默失败——90% 是环境差异:cron 默认 $PATH 极简(通常只有 /usr/bin:/bin),而 mysqldump 可能装在 /usr/local/mysql/bin,根本找不到。
不要依赖 ~/.bashrc 或 /etc/profile,cron 不加载这些。直接在脚本开头写:
export PATH="/usr/bin:/bin:/usr/local/mysql/bin" cd /backup/mysql || exit 1
- 所有命令用绝对路径:
/usr/bin/mysqldump、/bin/gzip、/usr/bin/find - 重定向 stderr 到日志:
2>> /var/log/mysql_backup.log,否则错误全丢掉 - 定时任务必须用
sudo crontab -e编辑 root 的任务(备份需读 MySQL 配置、写系统路径)
备份脚本必须检查退出码和文件大小,否则就是假成功
常见陷阱:mysqldump 因权限/连接超时/磁盘满失败,却生成一个空 .sql 文件,后续 gzip 和 find 照常执行,日志里还显示“success”——你根本不知道备份是空壳。
关键校验三步走:set -e 让任意命令失败立即退出;导出后立刻检查文件非空;压缩前确认 mysqldump 退出码为 0。
- 文件名必须含秒级时间戳:
$(date +\%Y\%m\%d_\%H\%M\%S)(反斜杠转义 %,防 shell 解析错误),避免同天多次运行覆盖 - 清理旧备份别用
-mtime +7:它按「修改时间」删,不是按文件名日期。某次备份失败留下空文件,-mtime会放过它;真正该删的成功备份反而可能被误删 - 清理优先按文件名日期匹配:
find /backup -name "db_????????_*.sql.gz" -regex ".*[0-9]\{8\}_[0-9]\{6\}.*" | sort -r | tail -n +8 | xargs rm -f
mysqldump 参数对不对、~/.my.cnf cron 能不能读到、退出码有没有被检查——漏掉任一,备份就可能静默失效。最危险的不是失败,是让你以为它成功了。











