先确保 mysqldump 能连库导出数据,再写定时任务;需检查登录权限、加 --single-transaction(innodb)或 --lock-all-tables(myisam)、导出存储过程与触发器、转义日期格式、设置写入目录权限。

用 mysqldump 命令手动备份一次,确认能跑通
别急着写定时任务,先确保 mysqldump 本身在当前环境能连上库、导出数据。常见失败原因是权限或网络问题,不是脚本写得不对。
执行前检查:mysql -u root -p 能登录,说明账户没问题;再试导出单个库:
mysqldump -u root -p --single-transaction --routines --triggers --events mydb > /tmp/mydb_$(date +\%Y\%m\%d).sql
-
--single-transaction对 InnoDB 很关键,避免锁表;MyISAM 必须加--lock-all-tables才一致 -
--routines和--triggers默认不导出存储过程和触发器,漏了恢复时会丢逻辑 - 日期格式里
%要转义成\%Y\%m\%d,否则 shell 会报错:invalid date - 输出路径必须有写权限,
/tmp可临时验证,正式环境建议用独立目录如/backup/mysql
写一个可复用的备份脚本,带压缩和保留策略
单纯 mysqldump 输出 SQL 文件体积大、传输慢,不压缩没法长期存。每天全量备份还要控制磁盘占用,得自动清理旧文件。
示例脚本 /usr/local/bin/backup_mysql.sh(记得 chmod +x):
#!/bin/bash
DB_USER="backup_user"
DB_PASS="xxx"
DB_NAME="mydb"
BACKUP_DIR="/backup/mysql"
DATE=$(date +\%Y\%m\%d_\%H\%M)
<p>mkdir -p $BACKUP_DIR
mysqldump -u $DB_USER -p$DB_PASS --single-transaction --routines --triggers --events $DB_NAME | gzip > $BACKUP_DIR/${DB<em>NAME}</em>$DATE.sql.gz</p><h1>只留最近 7 天</h1><p>find $BACKUP_DIR -name "${DB<em>NAME}</em>*.sql.gz" -mtime +7 -delete</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill2334" title="MySQL"><img
src="https://img.php.cn/upload/skill/000/000/081/178900927846657.jpg" alt="MySQL" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill2334" title="MySQL" class="overflowclass">MySQL</a>
<p class="overflowclass">编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。</p>
</div>
<a rel="nofollow" href="/xiazai/skill2334" title="MySQL" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- 密码直接写在命令行(
-p$DB_PASS)虽方便,但ps aux可见明文;更安全的做法是用~/.my.cnf配置文件,且权限设为600 -
gzip接在管道后,不落地中间 SQL 文件,省 I/O 和空间 -
find ... -mtime +7按“修改时间”删,不是“创建时间”,所以得确保备份文件写入后没被其他进程改过 - 如果备份多个库,把
DB_NAME改成数组循环,别硬写多遍mysqldump
用 crontab 设置每天凌晨 2 点自动执行
crontab 是最轻量、无需额外服务的定时方案,但要注意环境变量和路径问题 —— 它默认不加载你的 ~/.bashrc,mysqldump 可能找不到。
编辑 root 的 crontab:sudo crontab -e,加一行:
0 2 * * * /usr/local/bin/backup_mysql.sh >> /var/log/mysql_backup.log 2>&1
- 务必用绝对路径调用脚本和
mysqldump(可在脚本开头加PATH=/usr/local/bin:/usr/bin:/bin) -
>>追加日志,比覆盖更利于排查;2>&1把错误也记进去,不然 cron 静默失败你根本不知道 - 测试是否生效:把时间改成
* * * * *(每分钟跑),等两分钟看日志和文件生成情况,验证完立刻改回去 - 注意系统时区,
date和 cron 都按服务器本地时间走,别和你预期的 UTC 时间混淆
备份后必须验证,不能只看文件生成了就放心
每天生成一堆 .sql.gz 文件不代表备份有效。曾见过 gzip 文件头损坏、mysqldump 因连接超时中途退出却没报错、甚至磁盘满导致写入 0 字节的情况。
- 加一句校验:脚本末尾用
gunzip -t ${file}.gz测试能否解压,失败就发邮件或写告警日志 - 每周抽一个备份文件,用
zcat xxx.sql.gz | head -n 100看前几行是不是合法 SQL(含CREATE TABLE或INSERT) - 真正恢复测试不用每天做,但至少每季度在测试机上完整走一遍:解压 → 导入 → 查几条关键数据
- 如果用了 GTID 或主从复制,备份时加
--set-gtid-purged=OFF,否则恢复到不同环境可能报错
定时备份最难的不是写脚本,而是让验证成为固定动作。没人检查的备份,和没备份一样。










