15%

全场主机优惠15%

测试技能,享折扣

使用代码:

Skills
开始使用
09.10.2024

mysqldump终极指南:MySQL数据库备份、恢复与自动化

mysqldump 是一个与 MySQL 和 MariaDB 捆绑的命令行工具,通过将数据库对象和数据序列化为一系列 SQL 语句来生成逻辑备份。生成的转储文件可以在任何兼容服务器上重建相同的数据库,使其成为备份、跨服务器迁移、版本升级和灾难恢复工作流的行业标准工具。

与 Percona XtraBackup 或 MySQL Enterprise Backup 等物理备份工具不同,mysqldump 在 SQL 层运行——它通过 MySQL 协议读取实时数据,并写入可移植的、人类可读的 SQL。这种可移植性是其最大优势,而在大规模场景下,也是其主要限制。

mysqldump 底层实际工作原理

当您调用 mysqldump 时,客户端连接到 MySQL 服务器,查询信息模式和数据字典,并将 `CREATE DATABASE`、`CREATE TABLE`、`INSERT` 和 DDL 语句流输出到标准输出。您将该流重定向到文件、管道或压缩工具。

对于使用 `–single-transaction` 的 InnoDB 表,mysqldump 在读取任何数据之前会开启一个可重复读事务。这为您提供了一致的时间点快照,而无需获取全局读锁——在转储期间数据库保持完全可写状态。对于 MyISAM 表,不存在此类机制;mysqldump 会回退到 `FLUSH TABLES WITH READ LOCK`,这会短暂阻塞写操作。

在为生产工作负载选择 mysqldump 之前,理解这一区别至关重要。如果您的模式混合了 InnoDB 和 MyISAM 表,仅使用 `–single-transaction` 是不够的——您需要 `–lock-all-tables` 或维护窗口。

前提条件和所需权限

在运行任何转储命令之前,请验证以下内容:

  • MySQL 或 MariaDB 已安装并可访问(本地套接字或 TCP/IP)。
  • 备份用户拥有最低所需权限:
  • 对所有目标表的 `SELECT`
  • `LOCK TABLES`(除非仅对 InnoDB 使用 `–single-transaction`)
  • `SHOW VIEW` 以包含视图
  • `TRIGGER` 以包含触发器
  • 在 MySQL 8+ 上使用 `–single-transaction` 时需要 `PROCESS`
  • `FLUSH TABLES WITH READ LOCK` 需要 `RELOAD`
  • 如果需要用于复制设置的二进制日志坐标,则需要 `REPLICATION CLIENT`

创建专用备份用户,而不是以 root 身份运行转储:

“`sql

CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'StrongPassword!';

GRANT SELECT, LOCK TABLES, SHOW VIEW, TRIGGER, PROCESS, RELOAD, REPLICATION CLIENT

ON *.* TO 'backup_user'@'localhost';

FLUSH PRIVILEGES;

“`

以 root 身份运行 mysqldump 并在 shell 命令中嵌入密码会在进程列表和 shell 历史记录中暴露凭据——这在任何共享或多用户系统上都是重大安全风险。

基本语法

“`

mysqldump [OPTIONS] database_name [table1 table2 …] > backup_file.sql

“`

组件描述
`[OPTIONS]`控制连接、输出格式和行为的标志
`database_name`要导出的目标数据库
`[table1 table2 …]`可选:将转储限制为特定表
`> backup_file.sql`将标准输出重定向到文件

完整选项参考

连接选项

选项描述
`-u` / `–user`MySQL 用户名
`-p` / `–password`提示输入密码(切勿内联嵌入)
`-h` / `–host`主机名或 IP 地址(默认:localhost)
`-P` / `–port`TCP 端口(默认:3306)
`–socket`本地连接的 Unix 套接字路径
`–ssl-ca`用于加密连接的 CA 证书

范围选项

选项描述
`–databases db1 db2`转储多个指定数据库
`–all-databases`转储服务器上的所有数据库
`–tables`限制为特定表(覆盖 `–databases`)
`–ignore-table=db.tbl`排除特定表;可重复使用
`–where='condition'`仅导出符合 WHERE 子句的行

一致性和锁定选项

选项描述
`–single-transaction`无锁的一致 InnoDB 快照
`–lock-all-tables`用于混合引擎模式的全局读锁
`–lock-tables`按数据库锁定表(非 InnoDB 的默认值)
`–flush-logs`在转储前轮换二进制日志
`–master-data=2`将二进制日志位置写入注释(用于复制)
`–source-data=2`MySQL 8.0.26+ 中替代 `–master-data` 的选项

输出和内容选项

选项描述
`–no-data`仅导出模式,不含行数据
`–no-create-info`仅导出数据,不含 CREATE TABLE 语句
`–add-drop-table`在每个 CREATE TABLE 之前添加 DROP TABLE
`–add-drop-database`在 CREATE DATABASE 之前添加 DROP DATABASE
`–routines`包含存储过程和函数
`–triggers`包含触发器(默认启用)
`–events`包含计划事件
`–comments`包含元数据注释(默认启用)
`–compact`抑制注释和额外 SQL 以减小输出大小
`–hex-blob`将 BLOB/BINARY 列转储为十六进制字面量
`–column-statistics=0`禁用 ANALYZE TABLE 语句(MySQL 8 客户端对旧版服务器)

mysqldump 与其他备份方法的比较

选择正确的备份策略取决于数据库大小、RTO/RPO 要求和基础设施。以下是 mysqldump 与最常见替代方案的比较:

功能mysqldumpPercona XtraBackupMySQL Enterprise Backup二进制日志备份
备份类型逻辑(SQL)物理(文件级)物理(文件级)增量(binlog)
可移植性优秀依赖服务器版本依赖服务器版本需要基础备份
一致性(InnoDB)是(`–single-transaction`)是(热备份)是(热备份)
一致性(MyISAM)需要锁定需要锁定需要锁定不适用
速度(大型数据库)非常快(增量)
恢复速度慢(重放 SQL)快(文件复制)快(文件复制)需要基础备份 + 重放
人类可读输出
时间点恢复否(仅快照)是(配合 binlog)是(配合 binlog)
费用免费(捆绑)免费(开源)商业许可证免费(捆绑)
最佳使用场景中小型数据库、迁移大型生产数据库企业环境持续复制

对于 VPS Hosting 环境中 10–20 GB 以下的数据库,mysqldump 仍然是最实用、最具可移植性的解决方案。超过该阈值后,物理备份工具可提供显著更快的备份和恢复窗口。

实际使用示例

示例 1:备份单个数据库

“`bash

mysqldump -u backup_user -p database_name > /backups/database_name_$(date +%F).sql

“`

`$(date +%F)` 替换会自动将 ISO 日期(例如 `2025-07-15`)附加到文件名,防止覆盖。

示例 2:备份多个指定数据库

“`bash

mysqldump -u backup_user -p –databases app_db analytics_db > /backups/multi_db_backup.sql

“`

`–databases` 标志使 mysqldump 输出 `CREATE DATABASE` 和 `USE` 语句,使转储文件在恢复时自包含。

示例 3:备份所有数据库

“`bash

mysqldump -u backup_user -p –all-databases –events –routines –triggers

> /backups/full_server_$(date +%F).sql

“`

在完整服务器转储中始终包含 `–events`、`–routines` 和 `–triggers`。如果没有明确的标志,这些对象会被静默省略。

示例 4:一致的 InnoDB 备份(生产安全)

“`bash

mysqldump -u backup_user -p

–single-transaction

–flush-logs

–source-data=2

–routines –triggers –events

database_name > /backups/database_name_$(date +%F).sql

“`

`–flush-logs` 在转储开始时轮换二进制日志。`–source-data=2` 将当前二进制日志文件名和位置写入 SQL 注释,通过从该位置重放后续 binlog 来实现时间点恢复。

示例 5:使用 gzip 压缩备份

“`bash

mysqldump -u backup_user -p database_name | gzip -9 > /backups/database_name_$(date +%F).sql.gz

“`

对于 CPU 受限的服务器,替换为 `pigz`(并行 gzip)以利用多核:

“`bash

mysqldump -u backup_user -p database_name | pigz -9 > /backups/database_name_$(date +%F).sql.gz

“`

示例 6:仅模式备份(不含数据的结构)

“`bash

mysqldump -u backup_user -p –no-data database_name > /backups/schema_only.sql

“`

适用于在 Git 中对模式进行版本控制,或在不复制生产数据的情况下部署到预发布环境。

示例 7:仅数据备份(不含模式)

“`bash

mysqldump -u backup_user -p –no-create-info database_name > /backups/data_only.sql

“`

当目标模式已存在且只需填充或刷新数据时使用。

示例 8:备份单个表

“`bash

mysqldump -u backup_user -p database_name orders > /backups/orders_table_$(date +%F).sql

“`

示例 9:导出过滤后的行子集

“`bash

mysqldump -u backup_user -p database_name orders

–where="created_at >= '2025-01-01' AND status='completed'"

> /backups/orders_2025_completed.sql

“`

`–where` 选项使用不足,但对于部分导出、数据归档和调试特定记录集非常强大。

示例 10:排除特定表

“`bash

mysqldump -u backup_user -p database_name

–ignore-table=database_name.cache

–ignore-table=database_name.sessions

> /backups/database_name_no_cache.sql

“`

排除大型临时表(缓存、会话存储、日志表)可以将转储大小和持续时间减少一个数量级。

示例 11:包含存储过程、函数和触发器

“`bash

mysqldump -u backup_user -p –routines –triggers –events database_name > /backups/full_backup.sql

“`

示例 12:远程数据库备份

“`bash

mysqldump -u backup_user -p -h 192.168.1.100 -P 3306 database_name

gzip > /backups/remote_db_$(date +%F).sql.gz

“`

备份远程服务器时,默认情况下流量以未加密方式传输。添加 `–ssl-ca`、`–ssl-cert` 和 `–ssl-key` 标志,或通过 SSH 隧道传输:

“`bash

ssh user@remote-server "mysqldump -u backup_user -p database_name | gzip"

> /backups/remote_db_$(date +%F).sql.gz

“`

恢复 mysqldump 备份

恢复单个数据库

“`bash

mysql -u root -p database_name < /backups/database_name_2025-07-15.sql

“`

如果目标数据库尚不存在,请先创建它:

“`bash

mysql -u root -p -e "CREATE DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

mysql -u root -p database_name < /backups/database_name_2025-07-15.sql

“`

从完整服务器转储恢复所有数据库

“`bash

mysql -u root -p < /backups/full_server_2025-07-15.sql

“`

由于 `–all-databases` 嵌入了 `CREATE DATABASE` 和 `USE` 语句,不需要目标数据库参数。

从压缩备份恢复

“`bash

gunzip < /backups/database_name_2025-07-15.sql.gz | mysql -u root -p database_name

“`

或使用进程替换:

“`bash

mysql -u root -p database_name < <(gunzip -c /backups/database_name_2025-07-15.sql.gz)

“`

从完整数据库转储中恢复单个表

这是一个常见的操作场景,原始转储文件使其变得不简单。使用 `sed` 或 `grep` 提取相关部分:

“`bash

sed -n '/^– Table structure for table `orders`/,/^– Table structure for table `/p'

backup_file.sql | head -n -1 | mysql -u root -p database_name

“`

或者,使用 `mysql_extract_table.sh` 或导入到临时数据库并复制表:

“`bash

mysql -u root -p temp_restore < backup_file.sql

mysql -u root -p -e "INSERT INTO database_name.orders SELECT * FROM temp_restore.orders;"

“`

使用二进制日志进行时间点恢复

如果您的转储是使用 `–source-data=2` 进行的,并且启用了二进制日志记录,则可以恢复到转储后的任意时间点:

  1. 从转储文件头注释中识别二进制日志位置。
  2. 恢复基础转储。
  3. 将后续二进制日志事件应用到所需时间戳:

“`bash

mysqlbinlog –start-position=154 –stop-datetime="2025-07-15 14:30:00"

/var/lib/mysql/binlog.000042 | mysql -u root -p database_name

“`

使用 Cron 自动化备份

基本每日备份任务

将凭据存储在 `~/.my.cnf` 中,而不是将其嵌入 cron 命令:

“`ini

[mysqldump]

user=backup_user

password=StrongPassword!

“`

设置严格权限:

“`bash

chmod 600 ~/.my.cnf

“`

然后创建 cron 任务:

“`bash

crontab -e

“`

“`

Daily compressed backup at 02:00, retained for 30 days

0 2 * * * mysqldump –single-transaction –routines –triggers –events database_name

gzip -9 > /backups/database_name_$(date +%F).sql.gz

Delete backups older than 30 days

10 2 * * * find /backups/ -name "*.sql.gz" -mtime +30 -delete

“`

生产级备份脚本

对于托管多个数据库的 Dedicated Servers,更健壮的脚本可处理错误日志记录、磁盘空间检查和远程卸载:

“`bash

#!/bin/bash

BACKUP_DIR="/backups/mysql"

RETENTION_DAYS=30

LOG_FILE="/var/log/mysql_backup.log"

DATE=$(date +%F_%H-%M)

DATABASES=$(mysql –defaults-file=/etc/mysql/backup.cnf -e "SHOW DATABASES;"

grep -Ev "(Databaseinformation_schemaperformance_schemasys)")

mkdir -p "$BACKUP_DIR"

for DB in $DATABASES; do

OUTPUT="$BACKUP_DIR/${DB}_${DATE}.sql.gz"

mysqldump –defaults-file=/etc/mysql/backup.cnf

–single-transaction –routines –triggers –events

"$DB" | gzip -9 > "$OUTPUT"

if [ $? -eq 0 ]; then

echo "$(date): SUCCESS – $DB -> $OUTPUT" >> "$LOG_FILE"

else

echo "$(date): FAILURE – $DB" >> "$LOG_FILE"

fi

done

find "$BACKUP_DIR" -name "*.sql.gz" -mtime +"$RETENTION_DAYS" -delete

“`

mysqldump 操作的安全加固

凭据管理是备份安全中最常被忽视的方面。切勿在命令行上直接传递 `-pYourPassword`——它在 `ps aux` 输出和 shell 历史记录中可见。请改用以下方法之一:

  • `~/.my.cnf` 配合 `chmod 600`(按用户)
  • `/etc/mysql/backup.cnf` 配合 `chmod 640`,由 root 拥有,备份组可读
  • 环境变量 `MYSQL_PWD`(在 `/proc` 中可见,仅在隔离容器中使用)
  • MySQL Vault 或 HashiCorp Vault 用于企业环境

备份文件权限必须严格限制:

“`bash

chmod 640 /backups/database_name_2025-07-15.sql.gz

chown root:backup_group /backups/database_name_2025-07-15.sql.gz

“`

静态加密:对于敏感数据,在存储或传输前加密备份文件:

“`bash

mysqldump –single-transaction database_name

gzip
openssl enc -aes-256-cbc -salt -pbkdf2 -pass pass:"$BACKUP_PASSPHRASE"

> /backups/database_name_$(date +%F).sql.gz.enc

“`

传输加密:从远程服务器转储时,始终使用 SSL/TLS 或 SSH 隧道。在 VPS with cPanel 环境中,cPanel 的备份界面会自动处理此问题,但手动 mysqldump 操作需要明确的 SSL 标志。

常见陷阱及如何避免

字符集不匹配是导致恢复损坏最常见的原因。始终明确指定字符集:

“`bash

mysqldump –default-character-set=utf8mb4 database_name > backup.sql

mysql –default-character-set=utf8mb4 database_name < backup.sql

“`

缺少 `–column-statistics=0` 会导致 MySQL 8.0 客户端从 MySQL 5.7 或 MariaDB 服务器转储时失败。MySQL 8 客户端尝试转储旧版服务器不支持的列统计信息:

“`bash

mysqldump –column-statistics=0 -u backup_user -p database_name > backup.sql

“`

忘记 `–routines`、`–triggers` 和 `–events` 会静默省略关键数据库对象。这些标志默认未启用(除 `–triggers` 外),在临时转储中经常被遗忘。

大表转储导致 OOM:mysqldump 默认将整个结果集缓冲在内存中。对于非常大的表,添加 `–quick`(大多数版本默认启用,但值得验证)以逐行流式传输而不是缓冲:

“`bash

mysqldump –quick –single-transaction database_name > backup.sql

“`

恢复到不同 MySQL 版本:来自 MySQL 8.0 的转储可能包含 MySQL 5.7 不支持的语法(例如,函数索引、不可见列)。在依赖跨版本迁移之前,始终在版本匹配的环境中测试恢复。

自动增量值漂移:如果将表恢复到已有行的现有模式中,`INSERT` 语句将因主键冲突而失败,除非包含 `–add-drop-table` 或手动先截断目标表。

使用 mysqldump 进行数据库迁移

mysqldump 是在服务器之间迁移数据库的标准方法——例如,将 WordPress 站点从 Shared Web Hosting 迁移到 VPS,或迁移到具有更多资源的 VPS Control Panels 环境。

推荐的迁移工作流:

  1. 使用完整选项转储源数据库:

“`bash

mysqldump –single-transaction –routines –triggers –events

–default-character-set=utf8mb4 source_db | gzip > migration.sql.gz

“`

  1. 通过 SSH 使用 rsync 安全传输:

“`bash

rsync -avz -e ssh migration.sql.gz user@target-server:/tmp/

“`

  1. 使用匹配的字符集创建目标数据库:

“`bash

mysql -u root -p -e "CREATE DATABASE target_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

“`

  1. 恢复并验证:

“`bash

gunzip < /tmp/migration.sql.gz | mysql -u root -p target_db

mysql -u root -p target_db -e "SHOW TABLES; SELECT COUNT(*) FROM critical_table;"

“`

  1. 更新应用程序配置以指向新的数据库主机。

对于同样依赖电子邮件基础设施的应用程序,请确保 DNS 记录和 Email Hosting 配置与数据库迁移同步更新,以避免服务中断。

验证备份完整性

从未经过测试的备份不是备份——它只是一个未经验证的假设。实施验证例程:

“`bash

#!/bin/bash

Restore backup to a test database and verify row counts

TEST_DB="backup_verify_$(date +%s)"

BACKUP_FILE="/backups/database_name_$(date +%F).sql.gz"

mysql -u root -p -e "CREATE DATABASE $TEST_DB;"

gunzip < "$BACKUP_FILE" | mysql -u root -p "$TEST_DB"

PROD_COUNT=$(mysql -u root -p -sN -e "SELECT COUNT(*) FROM database_name.orders;")

TEST_COUNT=$(mysql -u root -p -sN -e "SELECT COUNT(*) FROM $TEST_DB.orders;")

if [ "$PROD_COUNT" -eq "$TEST_COUNT" ]; then

echo "Backup verified: row counts match ($PROD_COUNT rows)"

else

echo "BACKUP VERIFICATION FAILED: prod=$PROD_COUNT, test=$TEST_COUNT"

fi

mysql -u root -p -e "DROP DATABASE $TEST_DB;"

“`

通过 cron 每周运行此验证脚本,并在失败时发出警报。

决策矩阵:何时使用 mysqldump

场景使用 mysqldump?推荐替代方案
数据库 < 5 GB,任何引擎
数据库 5–50 GB,仅 InnoDB是(配合 `–single-transaction`)XtraBackup 可更快恢复
数据库 > 50 GB,生产环境有条件Percona XtraBackup 或 MySQL Enterprise Backup
跨版本迁移
跨平台迁移
部分表导出是(`–where`)
模式版本控制是(`–no-data`)
需要近零 RTO物理备份 + binlog 流
持续复制设置部分(`–source-data=2`)XtraBackup 配合 GTID
混合 InnoDB/MyISAM 模式是(配合 `–lock-all-tables`)XtraBackup

技术关键要点清单

  • 对于仅 InnoDB 的数据库,始终使用 `–single-transaction` 以避免备份期间的写锁。
  • 在任何旨在作为完整备份的转储中,始终包含 `–routines –triggers –events`。
  • 将凭据存储在 `~/.my.cnf` 或具有 `chmod 600/640` 的 `/etc/mysql/backup.cnf` 中——切勿内联在脚本或 cron 命令中。
  • 在针对 MySQL 5.7 或 MariaDB 服务器使用 MySQL 8.0 客户端时,添加 `–column-statistics=0`。
  • 在转储和恢复时始终指定 `–default-character-set=utf8mb4` 以防止字符编码损坏。
  • 使用 gzip 或 pigz 压缩所有备份;在异地传输前使用 AES-256 加密敏感转储。
  • 在生产转储中包含 `–flush-logs –source-data=2` 以通过二进制日志实现时间点恢复。
  • 使用 `find … -mtime +N -delete` 自动化保留清理以防止磁盘耗尽。
  • 按计划测试恢复——验证行数并对照生产数据进行抽查数据完整性。
  • 对于混合引擎模式,使用 `–lock-all-tables` 而不是 `–single-transaction` 以保证一致性。

常见问题

mysqldump 在备份期间会锁定表吗?

在纯 InnoDB 数据库上使用 `–single-transaction` 时,除了短暂的初始刷新外,不会获取表锁。MyISAM 表始终需要读锁(`LOCK TABLES`),因为它们缺乏事务支持。混合引擎模式需要 `–lock-all-tables` 以获得一致的快照,这会在转储期间阻塞写操作。

如何仅备份数据库模式而不包含任何数据?

使用 `–no-data` 标志:`mysqldump -u backup_user -p –no-data database_name > schema.sql`。这会导出所有 `CREATE TABLE`、`CREATE VIEW`、存储过程和触发器,而不包含任何 `INSERT` 语句。

为什么我的 mysqldump 出现”列统计信息”错误?

这发生在 MySQL 8.0 客户端连接到 MySQL 5.7 或 MariaDB 服务器时。在命令中添加 `–column-statistics=0`。或者,将服务器升级到 MySQL 8.0,或使用与服务器版本匹配的客户端二进制文件。

mysqldump 能执行增量备份吗?

不能。mysqldump 始终对指定范围生成完整的逻辑转储。增量备份功能需要二进制日志归档(`mysqlbinlog`)与使用 `–flush-logs –source-data=2` 进行的基础 mysqldump 相结合。真正的增量物理备份需要 Percona XtraBackup 或 MySQL Enterprise Backup。

在不暴露密码的情况下自动化 mysqldump 的最安全方式是什么?

创建一个具有最低所需权限的专用 MySQL 备份用户,将其凭据存储在 `~/.my.cnf` 的 `[mysqldump]` 部分或具有 `chmod 600` 的单独选项文件中,并使用 `–defaults-file=/path/to/backup.cnf` 引用它。这种方法使凭据完全不出现在进程列表、shell 历史记录和 cron 任务定义中。

15%

全场主机优惠15%

测试技能,享折扣

使用代码:

Skills
开始使用