MySQL数据库定期备份脚本,mysqldump+压缩+过期
MySQL数据库定期备份脚本是线上站点和数据安全的基础保障。
这篇文章会带你用 mysqldump 导出数据库,用 gzip 压缩备份文件,再配合 crontab 定时执行,并让脚本自动删除超过保留天数的旧备份。
按本文操作,你最终能得到一套每天自动运行、占用空间可控、且能手动验证恢复的备份方案。
动手前先确认三件事
在写脚本之前,先确认服务器上已经具备下面的条件,避免执行到一半才发现缺东西。
- MySQL 客户端已安装:因为
mysqldump包含在客户端工具中,执行mysql --version能看到版本号就说明已安装。如果提示command not found,需要先安装mysql-client或对应数据库客户端组件。 - 备份账号有权限:建议单独创建一个备份账号,只授予
SELECT、LOCK TABLES、SHOW VIEW、EVENT和TRIGGER等备份所需权限,不要直接用 root 跑定时任务。 - 磁盘空间足够:备份目录至少预留数据库体积 2 倍以上的空间,压缩后一般会更小,但为了安全请留足余量。
确认以上三点后,就可以开始写脚本了。
编写备份脚本的完整代码
我习惯把脚本放在 /opt/mysql_backup/ 目录下,你也可以换成自己的路径。
先创建目录:
mkdir -p /opt/mysql_backup
然后新建脚本文件:
vim /opt/mysql_backup/backup_mysql.sh
粘贴下面的内容,注意替换数据库账号、密码和库名:
#!/bin/bash
# MySQL 定期备份脚本
# 功能:mysqldump 导出 + gzip 压缩 + 过期备份自动删除
BACKUP_DIR="/opt/mysql_backup" # 备份文件存放目录
DB_USER="backup_user" # 数据库备份账号
DB_PASS="你的密码" # 备份账号密码
DB_NAME="db1 db2" # 要备份的数据库,多个库用空格分隔
RETENTION_DAYS=7 # 备份文件保留天数
DATE=$(date +%Y%m%d_%H%M%S)
# 创建备份目录(如果不存在)
mkdir -p "$BACKUP_DIR"
# 使用 mysqldump 导出,并用 gzip 压缩
mysqldump -u"$DB_USER" -p"$DB_PASS" \
--databases $DB_NAME \
--single-transaction \
--routines --triggers \
--default-character-set=utf8mb4 \
| gzip > "$BACKUP_DIR/mysql_${DATE}.sql.gz"
# 删除超过保留天数的备份文件
find "$BACKUP_DIR" -type f -name "mysql_*.sql.gz" -mtime +"$RETENTION_DAYS" -exec rm -f {} \;
echo "备份完成:$BACKUP_DIR/mysql_${DATE}.sql.gz"
这里有几个关键参数说明一下:
--single-transaction:对 InnoDB 表实现一致性备份,备份过程中不锁表,适合生产库。--routines --triggers:导出存储过程、函数和触发器,防止恢复后缺少这些对象。--default-character-set=utf8mb4:避免中文乱码。find ... -mtime +7:删除 7 天前的文件,这里的数字对应RETENTION_DAYS。
保存后给脚本加执行权限:
chmod +x /opt/mysql_backup/backup_mysql.sh
直接手动跑一次,确认没有报错:
/opt/mysql_backup/backup_mysql.sh
如果备份成功,/opt/mysql_backup/ 目录下会出现一个 mysql_20250101_120000.sql.gz 类似的文件。
用 crontab 挂上每天定时执行
手动跑通后,下面设置定时任务。
执行 crontab -e 打开当前用户的 cron 表,追加一行:
0 3 * * * /bin/bash /opt/mysql_backup/backup_mysql.sh >> /opt/mysql_backup/backup.log 2>&1
这行的意思是每天凌晨 3 点执行一次备份脚本,并把输出写入日志。
保存后,确认 cron 服务正在运行:
systemctl status cron
如果系统是 CentOS,服务名可能是 crond,用 service crond status 查看。
看到 active (running) 就说明定时任务在正常排队。
常见报错和避坑指南
第一次写脚本最容易遇到下面几个问题,提前了解能省不少时间。
mysqldump: command not found
说明 MySQL 客户端不在 PATH 里。
可以先用 which mysqldump 找到完整路径,比如 /usr/local/mysql/bin/mysqldump,然后把脚本里的 mysqldump 替换成完整路径。
ERROR 1045 (28000): Access denied for user
备份账号权限不足或密码错误。
建议用下面语句创建专用账号:
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY '密码';
GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
备份文件是 0 字节
通常是账号权限不足导致导出失败,但脚本没有捕获错误。
建议在脚本开头加上 set -e,让任意命令执行失败时直接退出,避免生成无效空文件。
密码明文写在脚本里有风险
如果担心安全问题,可以把账号密码写入 /root/.my.cnf,然后脚本里不再传 -p 参数。
这样只有 root 能读取该文件,相对更安全。
find 的 -mtime 计算逻辑
-mtime +7 表示超过 7 天前的文件,不是删除最近 7 个文件。
如果你想按文件数量保留,可以用 ls -t | tail -n +n 的方式,但按天数是更常见的运维习惯。
最后验证一下备份是否真的可用
备份脚本跑通不代表万事大吉,如果恢复不了,备份就等于零。
建议每次调整脚本后,都做一次恢复测试。
下面是一条快速验证命令,把备份导入到一个新库:
gunzip -c /opt/mysql_backup/mysql_20250101_120000.sql.gz | mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS test_restore;" && \
gunzip -c /opt/mysql_backup/mysql_20250101_120000.sql.gz | mysql -uroot -p test_restore
执行后,用 mysql -uroot -p -e "USE test_restore; SHOW TABLES;" 查看是否成功导入表结构。
检查无误后删除测试库即可。
另外,crontab 日志也是验证的重要手段。
执行 cat /opt/mysql_backup/backup.log,能看到每次任务的输出和错误信息。
如果某个时间点没有记录,优先排查 cron 服务状态和脚本路径是否写错。
按照这套流程,你的 MySQL 数据库定期备份脚本就已经完整落地了。
建议每周抽查一次备份文件大小和压缩包完整性,尤其是在表结构变动比较大的时候。
如果后续遇到备份失败,优先排查账号权限、磁盘空间和脚本路径这三项。
希望这篇教程能帮你把备份任务稳定跑起来。