
MySQL 数据库备份与恢复实操指南
备份不是“生成一个文件”这么简单。一个可用的备份方案,至少要回答三个问题:哪些数据会被保存,故障后如何恢复到目标时间,以及备份文件是否真的能够恢复。本文从常见的 MySQL 逻辑备份入手,介绍备份、恢复、验证和自动化的操作方法,并说明物理备份适合什么场景,以及容易被忽略的边界。
示例主要适用于 MySQL 8.0,命令行工具通常随 MySQL 客户端安装。不同 MySQL 版本及发行版可能在选项、认证插件和默认行为上有所不同,生产执行前应先检查本机工具版本和帮助信息。
一、先确定要解决什么问题
备份策略取决于恢复目标。误删一张表、服务器磁盘损坏、需要迁移数据库,以及需要恢复到某个时间点,是不同的问题,对恢复速度和备份频率的要求也不同。
- 误操作后恢复单库或单表:逻辑备份便于查看和选择性导入,适合数据量不太大、恢复时间可接受的场景。
- 服务器或磁盘故障后恢复整实例:数据量较大时,物理备份通常更快,但需要匹配工具版本、准备步骤和数据目录操作。
- 恢复到误操作发生前的时间点:通常需要一次全量备份,加上持续保存的二进制日志(binlog),不能只依赖定时导出的 SQL 文件。
- 迁移或测试环境初始化:逻辑备份易于传输和筛选,但跨版本迁移仍需检查字符集、排序规则、SQL 语法和对象兼容性。
在制定方案前,至少记录数据量、可接受的数据丢失量(RPO)、可接受的恢复时间(RTO)、数据库版本、存储位置和备份保留周期。备份放在与数据库同一块磁盘上,无法应对磁盘损坏;只存一份,也无法应对文件损坏或误删除。
二、备份前检查
先确认客户端工具版本、服务地址、目标数据库和可用空间。备份文件可能接近数据库中逻辑数据的大小,压缩后也不能假定一定很小。
mysqldump --version
mysql --version
mysql -h 127.0.0.1 -P 3306 -u backup_user -p \
-e "SELECT VERSION(), @@datadir, @@log_bin;"
命令中的 -p 会交互式提示密码,不要写成 -p明文密码,也不要把密码直接放在脚本参数中。命令行参数可能被进程列表、日志或监控系统记录。自动化任务可使用权限受限的客户端配置文件,例如:
cat > /etc/mysql/backup-client.cnf <<'EOF'
[client]
host=127.0.0.1
port=3306
user=backup_user
password=替换为实际密码
EOF
chmod 600 /etc/mysql/backup-client.cnf
不同系统上的配置文件路径和权限管理方式可能不同。应确保只有执行备份的账号可读取该文件,并避免把它纳入代码仓库或普通日志。客户端配置文件可以减少密码出现在命令行中的风险,但文件本身仍包含凭据,必须妥善保管。
三、使用 mysqldump 做逻辑备份
mysqldump 通过连接数据库读取表结构和数据,并生成可由 MySQL 客户端执行的 SQL 文本。它不等同于复制数据目录:恢复时需要重新执行 SQL,数据量大时可能耗时较长。
1. 备份单个数据库
mkdir -p /var/backups/mysql
umask 077
mysqldump --defaults-extra-file=/etc/mysql/backup-client.cnf \
--single-transaction \
--routines --events --triggers \
--databases app_db \
> /var/backups/mysql/app_db_$(date +%F_%H%M%S).sql
--databases 后可以列出多个数据库。该选项会在导出文件中包含 CREATE DATABASE 和 USE 等语句,因此恢复时通常不必预先创建库。文件名包含时间,便于区分备份批次;umask 077 使新建文件默认仅当前用户可读写,具体效果仍受系统权限和目录权限影响。
2. 一致性选项的边界
--single-transaction 对 InnoDB 表使用单个事务读取一致性快照,通常可以在备份期间允许正常读写,而不需要对整库长期加读锁。这是常见在线逻辑备份的基础选项,但它只解决事务型表的一致性问题。
- MyISAM 等非事务型表不受该快照保护,备份期间仍可能发生数据变化。
- 备份期间若有
ALTER TABLE、RENAME TABLE、DROP TABLE等结构变更,导出结果可能不一致或失败。应在备份窗口避免 DDL,或采用适合业务的锁定、维护窗口和备份方案。 - 单个事务可能持续较久,增加历史版本保留压力;大库执行前应评估事务时长、磁盘空间和数据库负载。
--single-transaction不能代替完整的灾备方案,也不会自动包含 binlog。
如需确认表的存储引擎,可执行:
mysql --defaults-extra-file=/etc/mysql/backup-client.cnf \
-N -e "SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'app_db'
AND TABLE_TYPE = 'BASE TABLE';"
3. 备份全部业务库或整个实例
备份多个数据库时可显式列出名称,避免不小心带上不需要的库:
mysqldump --defaults-extra-file=/etc/mysql/backup-client.cnf \
--single-transaction \
--routines --events --triggers \
--databases app_db reporting_db \
> /var/backups/mysql/business_databases.sql
也可以使用 --all-databases 导出所有数据库,但这并不意味着已经完整备份了 MySQL 实例的全部运行状态。用户、授权和系统库的处理在不同版本中有差异;不要把系统库直接当作可移植的实例恢复包。生产环境应单独维护用户、角色和授权的恢复办法,并在目标版本上测试。
--routines 用于导出存储过程和函数,--events 用于导出事件,--triggers 用于导出触发器。触发器在 mysqldump 中通常默认会导出,仍建议在命令中明确写出,便于审阅意图。导出这些对象所需的权限取决于 MySQL 版本和具体操作,遇到权限错误时应按最小权限原则补充,而不是直接使用管理员账号长期运行任务。
4. 常用选项说明
--defaults-extra-file:从指定配置文件读取连接信息。该选项应放在命令行较前位置;客户端对选项文件的读取规则可能受版本影响,执行前可查看对应版本帮助。--quick:逐行读取表数据,避免将整张表一次性缓存到客户端内存。许多版本的mysqldump默认会启用它;需要确认时可显式加上。--no-tablespaces:在某些版本和权限配置下,可避免导出表空间相关语句及其权限要求。它会影响导出内容,不是通用的“修复权限”开关;只有确认目标恢复不需要这些语句时才使用。--set-gtid-purged:涉及 GTID 状态的选项,可能在导出文件中写入或调整 GTID 相关语句。不同场景会影响复制拓扑和目标实例状态,不要照抄教程里的固定值;应结合版本、是否启用 GTID、恢复目标及复制规划先做测试。--master-data等复制位置相关选项:在不同版本中存在名称和行为差异,可能涉及锁和 binlog 坐标。需要搭建副本或做时间点恢复时,应按当前版本文档设计流程,而不是仅靠一个参数猜测坐标。
四、检查备份文件并安全压缩
导出命令退出码为 0,只能说明命令正常结束,不代表备份内容必然完整可用。至少检查文件是否存在、大小是否合理,并进行实际恢复演练。可以先查看 SQL 文件开头和结尾:
head -n 20 /var/backups/mysql/app_db_YYYY-MM-DD_HHMMSS.sql
tail -n 20 /var/backups/mysql/app_db_YYYY-MM-DD_HHMMSS.sql
要压缩时,应保证导出失败不会被后续压缩命令掩盖。使用 Bash 时可以打开 pipefail,并通过临时文件避免把未完成的结果当成正式备份:
set -o pipefail
umask 077
tmp=/var/backups/mysql/app_db_$(date +%F_%H%M%S).sql.gz.tmp
final=${tmp%.tmp}
mysqldump --defaults-extra-file=/etc/mysql/backup-client.cnf \
--single-transaction --routines --events --triggers \
--databases app_db \
| gzip -c > "$tmp" \
&& gzip -t "$tmp" \
&& mv "$tmp" "$final"
gzip -t 检查压缩流是否可读,不会验证 SQL 是否能在目标 MySQL 上成功执行。临时文件与正式文件应位于同一文件系统,避免移动操作跨文件系统时产生非预期行为。部署到其他目录或对象存储时,还应确认传输完成后校验文件大小或校验和,并限制访问权限。
五、恢复逻辑备份
恢复操作会执行 SQL,可能创建、删除或覆盖对象。不要未经检查就把备份导入正在承载业务的实例。先确认目标地址、数据库名称、版本和可用空间,并优先恢复到隔离测试实例验证。
1. 恢复包含数据库创建语句的备份
如果备份由 --databases app_db 生成,可使用 MySQL 客户端导入:
mysql --defaults-extra-file=/etc/mysql/restore-client.cnf \
< /var/backups/mysql/app_db_YYYY-MM-DD_HHMMSS.sql
如文件经过 gzip 压缩:
gzip -dc /var/backups/mysql/app_db_YYYY-MM-DD_HHMMSS.sql.gz \
| mysql --defaults-extra-file=/etc/mysql/restore-client.cnf
管道执行失败时,应检查压缩解码端和 MySQL 客户端的退出状态。Bash 中可使用:
set -o pipefail
gzip -dc /var/backups/mysql/app_db_YYYY-MM-DD_HHMMSS.sql.gz \
| mysql --defaults-extra-file=/etc/mysql/restore-client.cnf
2. 恢复到指定数据库
如果备份使用的是 --databases,文件通常包含原数据库名的创建和切换语句,直接用 mysql 目标库名 不一定能把内容重定向到另一个库。需要换库名时,可在隔离环境中检查 SQL 文件,并按计划修改或生成不带建库语句的备份;不要对未经审阅的大文件盲目执行文本替换。
若备份通过 --no-create-db 等方式生成、文件中不包含建库语句和 USE 语句,可以先创建目标库再指定导入位置:
mysql --defaults-extra-file=/etc/mysql/restore-client.cnf \
-e "CREATE DATABASE app_restore
CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci;"
mysql --defaults-extra-file=/etc/mysql/restore-client.cnf app_restore \
< /var/backups/mysql/app_db_data_only.sql
字符集和排序规则应与应用及源库要求一致;示例中的排序规则适用于支持该规则的 MySQL 版本,旧版本可能不支持。恢复对象时还需考虑触发器、存储过程、事件中的数据库名称,以及创建对象所需的权限。
3. 恢复过程中不要忽略报错
默认情况下,客户端遇到 SQL 错误会返回非零状态,但 SQL 文件可能已经执行了一部分。恢复失败后不要简单地重新运行并认为会自动回滚:导入文件中的多条 DDL 和数据语句通常不是一个整体事务,重复执行可能导致重复数据、对象已存在或状态不一致。应查看客户端错误、目标库现状和日志,确定从干净库重建还是从失败位置继续。
恢复时若使用了会跳过错误或继续执行的客户端选项,可能得到“命令结束了但数据不完整”的结果。除非有明确的故障处理方案,不要为追求命令成功退出而忽略 SQL 错误。
六、数据一致性、DDL 与时间点恢复
逻辑备份通常适合恢复到备份生成时的数据状态;如果需要恢复到某个更精确的时间点,必须提前规划并保存 binlog。一个常见思路是定期完成全量备份,同时确保实例启用了二进制日志,并把日志安全地归档到独立存储。恢复时先导入合适的全量备份,再从对应位置重放 binlog 到目标时间或目标事件之前。
这不是“有 binlog 就一定能回到任意时刻”。必须知道全量备份对应的日志坐标或 GTID 状态,确保日志连续、未过期且没有损坏,并在恢复副本或隔离实例上演练。导入包含 GTID 状态语句的备份时,尤其要评估它对现有复制拓扑的影响。
MySQL 8.0 中可以查看二进制日志配置和状态:
mysql --defaults-extra-file=/etc/mysql/backup-client.cnf \
-e "SHOW VARIABLES LIKE 'log_bin';
SHOW BINARY LOG STATUS;"
不同小版本对查看日志状态的语法可能不同,旧版本可能使用其他语句。应以服务器实际版本支持的语法为准。单独保存 SQL 文件而不记录备份时间、源实例标识和相关日志位置,通常不足以构成可靠的时间点恢复方案。
七、何时选择物理备份
逻辑备份生成可读 SQL,跨环境迁移和单库恢复较方便;代价是导出与导入都需要逐行处理数据,大库可能耗时很长。物理备份直接备份数据库文件及相关状态,适合大数据量、追求较短恢复时间或需要频繁备份的场景,但对工具兼容性和恢复流程要求更高。
物理备份工具应根据 MySQL 版本、存储引擎和部署方式选择。例如 Percona XtraBackup 支持范围与具体版本有关,使用前必须核对其官方兼容矩阵和对应版本文档;不能假定任意版本的工具都能备份任意版本的 MySQL。MySQL Enterprise Backup 是另一种方案,通常涉及相应产品许可与部署条件。
物理备份常见流程包括:创建备份、准备(应用日志并使备份达到可恢复状态)、校验、恢复到空的数据目录,并按工具要求调整属主和启动服务。数据目录操作具有高风险,服务停止要求、恢复命令和文件布局因工具及版本而异,不应把某个命令模板不加验证地用于生产。尤其不能在数据库仍运行时,直接覆盖其正在使用的数据目录。
八、备份自动化的基本要求
定时任务除了执行备份,还应能够发现失败、清理过期文件和报告剩余空间。下面是一个偏基础的 Bash 示例,使用前需要替换路径和连接配置,并通过手动运行确认系统环境支持这些命令。
#!/usr/bin/env bash
set -euo pipefail
umask 077
backup_dir=/var/backups/mysql
cnf=/etc/mysql/backup-client.cnf
db=app_db
stamp=$(date +%F_%H%M%S)
tmp="$backup_dir/${db}_${stamp}.sql.gz.tmp"
out="$backup_dir/${db}_${stamp}.sql.gz"
mkdir -p "$backup_dir"
mysqldump --defaults-extra-file="$cnf" \
--single-transaction --routines --events --triggers \
--databases "$db" \
| gzip -c > "$tmp"
gzip -t "$tmp"
mv "$tmp" "$out"
find "$backup_dir" -type f -name "${db}_*.sql.gz" -mtime +14 -delete
此示例按文件修改时间删除超过 14 天的匹配文件。它不是完整的保留策略:应根据恢复点目标确定保留周期,排除正在写入的临时文件,确保清理范围不会匹配其他数据,并最好将备份复制到独立故障域。对于重要业务,还应接入监控和告警,检查备份是否按时生成、文件大小是否异常,以及最近一次恢复演练是否通过。
在 Cron 中运行时,环境变量和可执行文件路径可能与交互式终端不同。建议使用绝对路径、明确日志位置,并检查 Cron 用户是否有权限读取配置文件、写入备份目录和连接数据库。不要通过邮件或普通日志输出配置文件内容、数据库密码及敏感业务数据。
九、权限与备份文件安全
逻辑备份通常包含完整业务数据,可能比在线数据库更容易被复制和带离受控环境。应限制备份账号的访问权限、限制文件读取权限,对异地传输使用受保护的通道,并按组织要求加密存储和管理密钥。压缩不等于加密,任何能读取压缩文件的人仍可能还原其中的数据。
备份账号不应默认拥有实例管理员的全部权限。所需权限与 MySQL 版本、导出的对象、是否导出表空间信息、是否需要 GTID 或复制信息有关。先在测试环境以专用账号运行,记录缺少的具体权限,再按官方文档和实际操作范围授予权限。不要为了消除报错而直接授予不必要的全局高权限。
十、常见错误与排查顺序
- 备份文件是空的或明显偏小:检查命令退出码、错误输出、磁盘空间和管道状态。使用压缩管道时确认设置了
pipefail,不能只看 gzip 是否创建了文件。 - 备份时出现权限错误:区分连接失败、读取表权限不足和导出对象权限不足,按具体错误补齐最小必要权限;不要把错误信息重定向后就当作备份成功。
- 导入后缺少过程、事件或触发器:确认备份命令包含相应选项,检查目标实例是否允许相应功能及当前账号是否有创建权限。
- 导入提示字符集或排序规则不存在:通常是源端和目标端版本或配置不兼容。先在目标版本的隔离实例验证,再决定调整建库语句、排序规则或迁移方式。
- 恢复后行数不符:检查备份是否完整、目标库是否导入到正确位置、过程中是否出现 SQL 错误,以及源表是否包含非 InnoDB 引擎或备份期间发生 DDL。
- 重新导入导致重复或对象冲突:判断上次导入执行到哪里,不要未经检查就重复运行。需要从干净状态重建时,先确认目标库数据可丢弃并留有必要副本。
- 大库备份或恢复太慢:评估逻辑备份是否仍适用,检查客户端网络、磁盘 I/O、事务持续时间和目标端索引构建耗时。若 RTO 不满足要求,应测试物理备份或其他经验证的方案。
十一、把恢复演练纳入备份流程
最可靠的验证方式不是反复检查文件大小,而是在隔离的 MySQL 实例上实际恢复,并对关键表、对象和业务查询进行检查。演练时应记录恢复耗时、所需人工步骤、工具版本、权限问题和数据校验结果,并检查应用能否使用恢复后的数据。
建议至少验证以下事项:
- 备份文件可读取、压缩文件校验通过,且备份时间与源实例记录相符。
- 目标实例版本和字符集满足导入要求,导入过程没有未处理的 SQL 错误。
- 核心表的行数、关键汇总值或业务不变量符合预期。
- 视业务需要,存储过程、函数、触发器和事件均存在且能够正常工作。
- 如果目标是时间点恢复,确认备份与 binlog 衔接,并演练到指定时间或事件之前。
- 测量恢复耗时是否满足 RTO,并确认恢复账号、应用配置和访问控制没有误用生产凭据。
结语
对于数据量适中、需要灵活迁移或选择性恢复的场景,mysqldump 是易于理解和检查的起点。在线导出时,InnoDB 常用 --single-transaction 获得一致性快照,但它不能解决非事务表和备份期间 DDL 的问题,也不能替代 binlog 时间点恢复。数据量大、恢复时间要求严格时,应评估经过版本验证的物理备份方案。
无论选用哪种方式,真正的备份流程都应包括权限控制、独立存储、失败告警、保留策略和恢复演练。定期成功生成文件只是第一步;能够在目标环境中按预期恢复,才说明备份方案经受住了检验。








