部署前提和账户
部署目标:
- 源: WordPress博客的数据库
wordpress,运行在MySQL 8.0里- 目标: 每天凌晨3点自动备份到一个目录
/data/backup/mysql- 清理策略: 只保留最近7天的备份,过期自动删除
- 运维边界: 不用root跑,用你博客自己的数据库用户(后面会提到权限限制)
# 登录MySQL,查看当前用户权限mysql -u root -p SHOW GRANTS FOR '你的博客用户'@'localhost';
先跑通一条mysqldump命令
在服务器上终端先手工执行一次,确保能备份出来:
-u:数据库用户名-p:密码(后面写脚本会分离到配置文件)- 数据库名放在最后,重定向
>输出到文件mysqldump -u你的博客用户 -p你的密码 wordpress > /tmp/test_backup.sql
创建备份脚本(重点)
创建脚本 /opt/scripts/mysql_backup.sh 写入:
#!/bin/bash
# ===== 配置区 =====
BACKUP_DIR="/data/backup/mysql" # 备份存放目录
DB_NAME="wordpress" # 要备份的数据库
DB_USER="你的博客用户" # 数据库账号
DB_PASS="你的密码" # 数据库密码
RETENTION_DAYS=7 # 保留天数
# ===== 自动变量 =====
DATE=$(date +%Y%m%d_%H%M%S) # 当前时间戳
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.sql"
# ===== 确保备份目录存在 =====
mkdir -p $BACKUP_DIR
# ===== 执行备份 =====
mysqldump \
--single-transaction \
--routines \
--triggers \
-u$DB_USER \
-p$DB_PASS \
$DB_NAME > $BACKUP_FILE
# ===== 检查是否备份成功 =====
if [ $? -eq 0 ]; then
echo "[$(date)] 备份成功:$BACKUP_FILE" >> $BACKUP_DIR/backup.log
else
echo "[$(date)] 备份失败!" >> $BACKUP_DIR/backup.log
exit 1
fi
# ===== 清理7天前的旧备份 =====
find $BACKUP_DIR -name "*.sql" -mtime +$RETENTION_DAYS -delete
echo "[$(date)] 已清理${RETENTION_DAYS}天前的旧备份" >> $BACKUP_DIR/backup.log
代码详解
第 1 行:
/bin/bash 是 Bash 解释器的绝对路径
第 3-8 行:配置区:
BACKUP_DIR=”/data/backup/mysql”
DB_NAME=”wordpress”
DB_USER=”你的博客用户”
DB_PASS=”你的密码”
RETENTION_DAYS=7
- 变量命名习惯: 全大写表示常量/配置项,一目了然
- 为什么不用写死在命令里: 如果备份目录变了、数据库改名了,只改这里就行,不用去命令堆里找
RETENTION_DAYS=7: 保留 7 天的备份,7 天前的自动删除。如果以后想改成 30 天,只改这一个数字
第 11-12 行:自动变量:
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE=”$BACKUP_DIR/${DB_NAME}_${DATE}.sql”
11行: 生成一个时间戳字符串,避免每次备份文件名重复。
$(命令)是命令替换语法,把命令的输出结果赋值给变量date +%Y%m%d_%H%M%S会输出类似20260513_030000的时间戳%Y四位年份,%m两位月份,%d两位日期%H24小时制小时,%M分钟,%S秒
12行: 拼接出完整的备份文件路径。
${变量名}是变量引用的完整写法,防止变量和后面字符粘连- 拼接结果示例:
/data/backup/mysql/wordpress_20260513_030000.sql
第 15 行:
mkdir -p $BACKUP_DIR
作用: 确保备份目录存在。
详细解释:
mkdir创建目录-p参数:如果目录已存在不报错,如果父目录也不存在会一并创建(比如/data/backup/mysql三级一次性建好)- 没有
-p的话,目录不存在会报错中断脚本
第 18-23 行:执行备份:
mysqldump \
–single-transaction \
–routines \
–triggers \
-u$DB_USER \
-p$DB_PASS \
$DB_NAME > $BACKUP_FILE
第 18 行作用: 调用 mysqldump 命令,\ 表示换行继续(为了可读性,把长命令折成多行)。
第 19 行 --single-transaction:
- 对 InnoDB 表开启一个事务,在整个备份过程中读取事务开始时的快照数据
- 好处:备份期间不锁表,网站正常读写不受影响
- 这是生产环境备份的标配参数
第 20 行 --routines:
- 连存储过程(Stored Procedure)和函数一起备份
- WordPress 一般没有存储过程,但加上没坏处
第 21 行 --triggers:
- 连触发器(Trigger)一起备份
- 同样,WordPress 一般没有,但加了有备无患
第 22-23 行 -u$DB_USER -p$DB_PASS:
-u指定数据库用户名,-p指定密码- 注意
-p$DB_PASS之间没有空格——MySQL 命令行工具的规则,有空格的-p 密码会被误解为“交互式输入密码 + 密码是另一个参数”
第 24 行 $DB_NAME > $BACKUP_FILE:
- 指定要备份的数据库名
>是输出重定向,把 mysqldump 输出的 SQL 内容写入到$BACKUP_FILE文件里
第 27-32 行:检查备份是否成功
if [ $? -eq 0 ]; then
echo “[$(date)] 备份成功:$BACKUP_FILE” >> $BACKUP_DIR/backup.log
else
echo “[$(date)] 备份失败!” >> $BACKUP_DIR/backup.log
exit 1
fi
第 27 行 if [ $? -eq 0 ]; then:
详细拆解:
$?是 Shell 的特殊变量,保存了上一条命令的退出状态码0表示上一条命令(mysqldump)执行成功- 非
0表示出了某种错误(连接失败、权限不够、磁盘满等) [ ... ]是 test 命令的简写,做条件判断-eq是 equal 的意思,数字相等判断if; then开启条件分支
第 28 行:备份成功时做的事
echo "[$(date)] 备份成功:$BACKUP_FILE"- 输出类似:
[Mon May 13 03:00:00 CST 2026] 备份成功:/data/backup/mysql/wordpress_20260513_030000.sql >>是追加重定向,把内容追加到日志文件末尾,不会覆盖之前的日志$(date)不加格式参数时输出完整日期时间字符串,带星期和时区
第 30 行:备份失败时做的事
- 同样往日志写一行,标记失败
第 31 行 exit 1:
- 以退出码 1 终止脚本
- 1 表示异常退出,这样如果外面有其他脚本调用这个备份脚本,就能通过
$?知道它失败了
第 32 行 fi:
if语句的结束标记(if倒过来写)
第 35-36 行:清理旧备份
find $BACKUP_DIR -name “*.sql” -mtime +$RETENTION_DAYS -delete
echo “[$(date)] 已清理${RETENTION_DAYS}天前的旧备份” >> $BACKUP_DIR/backup.log
第 35 行作用: 删除 7 天前的旧备份文件,防止磁盘被撑满。
详细拆解 find 命令:
find $BACKUP_DIR:在备份目录下查找-name "*.sql":只匹配以.sql结尾的文件(避免误删日志或其他文件)-mtime +7:文件最后修改时间距今超过 7 天+7是“大于 7 天”7是“恰好 7 天前的那一天”-7是“小于 7 天”(最近 7 天内)
-delete:直接删除匹配的文件
第 36 行: 往日志追加一行清理记录,方便追踪。
设计考虑
第一个是配置集中管理,变量都放在开头,维护方便。
第二个是加入了成功/失败的判断和日志记录,不是盲跑,出了问题能追溯。
第三个是用 find -mtime 实现备份滚动清理,防止磁盘被占满。
第四个是 --single-transaction 参数保证备份期间业务不中断。
后续把密码迁移到 .my.cnf 凭证文件里,提高安全性。
密码安全处理(提高安全性可不加)
把密码明文写在脚本里是个安全漏洞。用MySQL的--defaults-extra-file机制隔离出来。
创建一个只有你的用户能读的配置文件:
# 写入配置文件
cat > /opt/scripts/.my.cnf <<EOF
[client]
user=你的博客用户
password=你的密码
EOF
#这里的 [client] 是选项组,它下面定义的 user 和 password 会被所有标准的 MySQL 客户端程序读取,例如 mysql 和 mysqldump。
# 最关键一步:将权限设为600,只有文件所有者可读写
chmod 600 /opt/scripts/.my.cnf
#如果权限设置太宽松(比如 644),mysqldump 等程序可能会因为认为文件不安全而拒绝读取它。
把脚本里的-u和-p参数全部换成:
mysqldump \
--defaults-extra-file=/opt/scripts/.my.cnf \
--single-transaction \
--routines \
--triggers \
$DB_NAME > $BACKUP_FILE
原代码:
mysqldump \
–single-transaction \
–routines \
–triggers \
-u$DB_USER \
-p$DB_PASS \
$DB_NAME > $BACKUP_FILE
ps:--defaults-extra-file 是一个命令行选项,用来告诉 MySQL 客户端程序(如 mysql, mysqldump)在一个额外的、用户指定的文件里读取配置参数。
定时执行(crontab)
执行顺序:
crontab -e

ps:第一次使用crontab会提示用哪个工具,注意区分,选1就行
进入编辑器后,用方向键把光标移到文件内容的最后一行空行,粘贴或手动输入:
0 3 * * * /bin/bash /opt/scripts/mysql_backup.sh
注意五个星号之间都要有空格,这个格式很严格:
- 分 时 日 月 周 命令
0 3 * * *表示每天凌晨 3 点 0 分
保存并退出 nano:
Ctrl + O(字母o)→ 回车确认保存- 选择保存位置:File Name to Write: /tmp/crontab.C9ND7V/crontab
Ctrl + X退出
最后确认定时任务生效:
crontab -l
屏幕上应该输出:
0 3 * * * /bin/bash /opt/scripts/mysql_backup.sh
只要看到这一行,就说明定时任务已经写入 root 的 crontab
确认生效
crontab -l # 查看当前定时任务
tail -f /data/backup/mysql/backup.log # 查看日志输出
恭喜你完成了所有步骤!