[1. 增量备份只备份了 mysql-bin.index](#1. 增量备份只备份了 mysql-bin.index)
[2. 增量备份为空或不完整](#2. 增量备份为空或不完整)
[3. 新增 binlog 文件数量增加](#3. 新增 binlog 文件数量增加)
[4. crontab 日志记录](#4. crontab 日志记录)
前言
在实际生产环境中,数据库备份是保障数据安全的重要环节。本文总结了基于 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`] 备份任务完成"
- 输出最终备份完成的提示。