前言
在实际生产环境中,数据库备份是保障数据安全的重要环节。本文总结了基于 RPM 安装的 MySQL 5.7 的全量 + 增量备份方案,结合遇到的问题和解决方法,为大家提供一个完整参考。
一、备份方案概述
全量备份:每周日使用
mysqldump备份所有数据库到 SQL 文件增量备份:每天基于 MySQL 二进制日志(binlog) 进行备份
自动清理:保留最近 7 天的备份文件
目录结构:
/var/lib/mysql/mysql_backup/
├── full/ # 全量备份目录
└── increment/ # 增量备份目录
二、最终备份脚本
#!/bin/bash
# MySQL 全量+增量备份脚本
# 配置区
BACKUP_ROOT=/var/lib/mysql/mysql_backup
FULL_DIR=$BACKUP_ROOT/full
INCR_DIR=$BACKUP_ROOT/increment
MYSQL_USER=root
MYSQL_PASS='123456'
DATE=$(date +%F)
WEEKDAY=$(date +%u)
BINLOG_DIR=/var/lib/mysql
RETENTION_DAYS=7
# 创建备份目录
mkdir -p $FULL_DIR
mkdir -p $INCR_DIR
# 每周日执行全量备份
if [ "$WEEKDAY" -eq 7 ]; then
echo "[`date`] 开始全量备份..."
FULL_FILE=$FULL_DIR/all_$DATE.sql
mysqldump -u$MYSQL_USER -p$MYSQL_PASS --all-databases --single-transaction --flush-logs > $FULL_FILE
if [ $? -eq 0 ]; then
echo "[`date`] 全量备份完成:$FULL_FILE"
else
echo "[`date`] 全量备份失败!"
fi
fi
# 每日增量备份(基于 binlog)
echo "[`date`] 开始增量备份..."
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "FLUSH LOGS;"
# 获取倒数第二个完整 binlog 文件
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.[0-9]* | tail -2 | head -1)
if [ -f "$PREV_BINLOG" ]; then
cp $PREV_BINLOG $INCR_DIR/$(basename $PREV_BINLOG).$DATE
if [ $? -eq 0 ]; then
echo "[`date`] 增量备份完成:$INCR_DIR/$(basename $PREV_BINLOG).$DATE"
else
echo "[`date`] 增量备份失败!"
fi
else
echo "[`date`] 没找到可用的 binlog 文件"
fi
# 自动删除 7 天前备份
echo "[`date`] 开始清理7天前的备份..."
find $FULL_DIR -type f -mtime +$RETENTION_DAYS -name "*.sql" -exec rm -f {} \;
find $INCR_DIR -type f -mtime +$RETENTION_DAYS -name "mysql-bin.*" -exec rm -f {} \;
echo "[`date`] 清理完成"
echo "[`date`] 备份任务完成"
测试截图

三、遇到的问题与解决方案
1. 增量备份只备份了 mysql-bin.index
现象:执行脚本后,增量备份目录中出现了 mysql-bin.index.日期 文件,而不是实际的 binlog 文件(如 mysql-bin.000002)。
原因:
原脚本中使用了:
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.* | tail -2 | head -1)
mysql-bin.*会匹配所有文件,包括.index文件如果目录中有
mysql-bin.index,shell 排序可能取到了索引文件,导致备份文件不包含实际事务数据
解决方案:
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.[0-9]* | tail -2 | head -1)
使用
mysql-bin.[0-9]*只匹配数字序号文件排除索引文件,保证增量备份内容完整
2. 增量备份为空或不完整
现象:新生成的 binlog 文件可能正在写入,直接备份会导致空或未完成事务。
原因:
脚本使用
SHOW MASTER STATUS获取当前 binlog 文件当前文件可能刚生成,还未写入任何事务
解决方案:
备份倒数第二个文件,而不是最新文件:
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.[0-9]* | tail -2 | head -1)
最新文件仍在写入,倒数第二个文件已经完成,可以安全备份
3. 新增 binlog 文件数量增加
现象:每次执行 FLUSH LOGS; 后,binlog 文件会生成新的序号,如 mysql-bin.000002。
原因:
MySQL
FLUSH LOGS;会滚动当前 binlog,生成新的文件是 MySQL 的标准行为,不是脚本错误
注意:
每次增量备份都应复制倒数第二个文件
保证备份完整、不会备份正在写入的文件
4. crontab 日志记录
脚本可以加入定时任务:
0 1 * * * /bin/bash /var/lib/mysql/mysql_backup/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
注意:
/var/log/mysql_backup.log路径不存在时,>>会自动创建文件,但父目录必须存在
四、总结
全量备份使用
mysqldump每周一次增量备份基于 binlog,注意只备份已完成的 binlog 文件
清理机制保证备份目录不无限膨胀
脚本问题排查要点:
增量备份误备份索引文件 → 用数字匹配避免
空增量备份 → 复制倒数第二个文件
binlog 文件不断增加 → FLUSH LOGS 导致,正常
日志管理:
全量备份使用
.sql文件增量备份使用
mysql-bin文件自动保留 7 天备份
脚本中常用参数:
ls -tr:按时间排序文件basename:去掉路径,只取文件名[ -f "$file" ]:判断普通文件是否存在$?:判断上一条命令是否成功
通过这套方案,可以在 MySQL RPM 安装环境下实现 安全、稳定、可自动化的全量 + 增量备份。
五、附录
rpm安装mysql步骤
1.下载RPM以及依赖包
# 下载 MySQL 5.7 的 YUM 仓库配置包
wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
# 安装 repo 配置包
sudo rpm -ivh mysql57-community-release-el7-11.noarch.rpm
2.下载MYSQL所需的依赖包
cd /opt
mkdir mysql5720_rpms
#--resolve 自动下载依赖,--destdir 指定保存目录
yumdownloader --resolve --destdir=/opt/mysql5720_rpms mysql-community-server-5.7.20
3.安装RPM包
cd /opt/mysql5720_rpms
yum localinstall -y *.rpm
4.启动mysql
systemctl start mysqld
5.修改初始密码
mysql -uroot -p$(grep "password" /var/log/mysqld.log | awk '{print $NF}') --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'Admin@123';"
6.修改配置文件
vim /etc/my.cnf
[mysqld]
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
port = 3306
bind-address = 0.0.0.0
default-storage-engine=INNODB
character-set-server=utf8
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
validate_password_policy=LOW # 降低强度策略(仅检查长度)
validate_password_length=6 # 最小密码长度设为6位
#log-bin=mysql-bin (可选:开启二进制日志)
#binlog_format=MIXED (可选:指定二进制日志的记录格式)
server-id=1
systemctl restart mysqld
7.修改密码
mysql -uroot -pAdmin@123 -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';"
8.测试登录
mysql -uroot -p123456
六、脚本参数详解
脚本逐行解析
#!/bin/bash
指定脚本解释器为
bash,保证脚本在 Linux 系统下用 Bash 执行。
配置区
BACKUP_ROOT=/var/lib/mysql/mysql_backup
备份根目录,所有备份文件都存放在这里。
FULL_DIR=$BACKUP_ROOT/full
INCR_DIR=$BACKUP_ROOT/increment
全量备份目录和增量备份目录,便于分类管理备份。
MYSQL_USER=root
MYSQL_PASS='123456'
MySQL 登录用户名和密码,用于执行
mysqldump和mysql命令。注意:命令行中使用密码会有安全提示,可使用
.my.cnf文件避免明文密码。
DATE=$(date +%F)
获取当前日期,格式为
YYYY-MM-DD,用于给备份文件命名。示例:
2025-10-01
WEEKDAY=$(date +%u)
获取当前星期几,1 = 星期一,7 = 星期日。用于判断是否执行全量备份。
BINLOG_DIR=/var/lib/mysql
MySQL 二进制日志目录(RPM 安装默认
/var/lib/mysql),用于增量备份。
RETENTION_DAYS=7
自动清理多少天前的备份文件,这里设置为 7 天。
创建备份目录
mkdir -p $FULL_DIR
mkdir -p $INCR_DIR
-p参数表示递归创建目录,如果目录已存在不会报错。保证备份目录存在,避免
cp或mysqldump写入失败。
全量备份(每周日执行)
if [ "$WEEKDAY" -eq 7 ]; then
echo "[`date`] 开始全量备份..."
FULL_FILE=$FULL_DIR/all_$DATE.sql
判断今天是否是星期日,如果是则执行全量备份。
全量备份文件命名为
all_YYYY-MM-DD.sql。
mysqldump -u$MYSQL_USER -p$MYSQL_PASS --all-databases --single-transaction --flush-logs > $FULL_FILE
mysqldump:MySQL 官方备份工具。参数解释:
-u$MYSQL_USER:登录用户名。-p$MYSQL_PASS:登录密码。--all-databases:备份所有数据库。--single-transaction:对 InnoDB 表启用一致性快照,避免锁表。--flush-logs:备份时刷新日志,生成新的二进制日志文件,便于增量备份。
> $FULL_FILE:将输出保存到全量备份文件。
if [ $? -eq 0 ]; then
echo "[`date`] 全量备份完成:$FULL_FILE"
else
echo "[`date`] 全量备份失败!"
fi
$?表示上一条命令执行状态码:0表示成功非 0 表示失败
根据状态输出备份结果。
增量备份(每天执行)
echo "[`date`] 开始增量备份..."
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "FLUSH LOGS;"
每次增量备份前执行
FLUSH LOGS;:MySQL 生成一个新的二进制日志文件(如
mysql-bin.000003)。保证增量备份文件完整。
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.[0-9]* | tail -2 | head -1)
获取最新两个 binlog 文件中倒数第二个(完整的上一个 binlog)。
参数解释:
ls -tr:-t:按修改时间排序(最新的在前)-r:反转顺序(最旧在前)
$BINLOG_DIR/mysql-bin.[0-9]*:匹配所有数字编号的 binlog 文件。tail -2 | head -1:取倒数第二个文件(上一次的 binlog,用于增量备份)。
if [ -f "$PREV_BINLOG" ]; then
cp $PREV_BINLOG $INCR_DIR/$(basename $PREV_BINLOG).$DATE
-f:判断文件是否存在且为普通文件。basename $PREV_BINLOG:获取文件名(去掉路径),避免复制时路径问题。cp ... $INCR_DIR/....$DATE:复制 binlog 到增量目录,并加日期后缀。
if [ $? -eq 0 ]; then
echo "[`date`] 增量备份完成:$INCR_DIR/$(basename $PREV_BINLOG).$DATE"
else
echo "[`date`] 增量备份失败!"
fi
判断复制是否成功,输出结果。
else
echo "[`date`] 没找到可用的 binlog 文件"
fi
如果
$PREV_BINLOG不存在,则输出警告。
自动删除过期备份
echo "[`date`] 开始清理7天前的备份..."
find $FULL_DIR -type f -mtime +$RETENTION_DAYS -name "*.sql" -exec rm -f {} \;
find $INCR_DIR -type f -mtime +$RETENTION_DAYS -name "mysql-bin.*" -exec rm -f {} \;
find:查找符合条件的文件并删除。参数解释:
$FULL_DIR/$INCR_DIR:查找路径。-type f:只查找普通文件。-mtime +$RETENTION_DAYS:修改时间超过$RETENTION_DAYS天。-name "*.sql"/"mysql-bin.*":匹配文件名。-exec rm -f {} \;:删除匹配文件。
echo "[`date`] 清理完成"
输出清理完成信息。
脚本结束
echo "[`date`] 备份任务完成"
输出最终备份完成的提示。
浙公网安备 33010602011771号