# MySQL 备份与恢复 ## 场景 定期备份数据库,出事了能恢复到某个时间点。 ## 前置条件 - 备份盘容量够,最好和数据库不在同一块盘 - 知道恢复的 RPO:能接受丢多久的数据 - 大库(上百 G)用物理备份,小库用逻辑备份 ## 配置 ### 逻辑备份(mysqldump,几十 G 以内) ```bash mysqldump -u root -p \ --single-transaction --routines --triggers --events \ --default-character-set=utf8mb4 \ --databases appdb > /backup/appdb_$(date +%F).sql gzip -9 /backup/appdb_$(date +%F).sql ``` ### 物理备份(Percona XtraBackup,大库) ```bash xtrabackup --backup --user=root --password=*** \ --target-dir=/backup/xtra/$(date +%F) xtrabackup --prepare --target-dir=/backup/xtra/$(date +%F) ``` ### 恢复 ```bash systemctl stop mysqld # 逻辑 mysql -u root -p appdb < /backup/appdb.sql # 物理 xtrabackup --copy-back --target-dir=/backup/xtra/2026-10-18 chown -R mysql:mysql /var/lib/mysql systemctl start mysqld ``` ## 验证 ```bash mysql -u root -p -e "SELECT COUNT(*) FROM appdb.orders;" mysql -u root -p -e "SHOW TABLE STATUS FROM appdb;" ``` 恢复完对一下关键表的行数和最新时间戳。 ## 回滚 恢复前先备份当前状态,恢复错了还能退回去: ```bash mv /var/lib/mysql /var/lib/mysql.broken ``` ## 坑 - **`--single-transaction` 只对 InnoDB 有效**,有 MyISAM 表会锁表。 - 不加 `--databases` 时导出的文件里没有 `CREATE DATABASE`,恢复要先建库。 - 乱码问题九成是导出/导入两端字符集不一致。 - `xtrabackup --prepare` 不能省,跳过去启不来。 - 备份文件不验证等于没有,定期拿一份真恢复一次。 - 主从环境恢复要处理 GTID,否则复制起不来。