mysqldump 导出的备份文件,本质上就是一份 SQL 脚本。
恢复时,本质上就是把这份 SQL 再交给 mysql 执行。
命令看起来不复杂,但真正容易踩坑的地方主要有这些:
-
恢复到测试服务器,还是恢复到源库
-
恢复全库,还是只恢复单库
-
备份文件里是否带了系统库
-
单库恢复时目标库是否提前创建
-
源库和目标库字符集、排序规则是否一致
-
恢复完成后如何快速核对结果
这篇文章就把这些关键点一次讲清楚。
一、恢复前先记住 4 个原则
1. 恢复前先看字符集和排序规则
尤其是从生产恢复到测试时,建议先对比源库和目标库的字符集、排序规则是否一致。
常用 SQL:
SHOW CREATE DATABASE demo_app;
或者:
SELECT schema_name, default_character_set_name, default_collation_name
FROM information_schema.schemata
WHERE schema_name = 'demo_app';
重点看两项:
-
default_character_set_name -
default_collation_name
如果两边不一致,恢复后可能会出现乱码、排序不一致、索引比较异常等问题。
2. 全库备份和单库恢复不是一回事
如果导出时用了:
mysqldump --all-databases
那备份文件里通常会带多几个系统库,甚至可能带 mysql 系统库。
这时候:
-
全库恢复:可以直接整体导入
-
单库恢复 :不能无脑直接导,要用
--one-database
3. 单库恢复时,目标库必须先存在
这是最容易忽略的点。
如果直接执行:
mysql --one-database demo_app -u root -p < all_no_mysql.sql
而目标实例里还没有 demo_app 这个库,就会报:
ERROR 1049 (42000): Unknown database 'demo_app'
所以单库恢复前,必须先把目标库建出来。
4. 恢复到测试服务器和恢复到源库,风险完全不同
恢复到测试服务器,主要是验证和测试,风险可控。
恢复到源库,直接影响业务,必须更谨慎。
一句话记住:
测试服务器恢复,重点是恢复成功。
源库恢复,重点是恢复安全。
二、恢复到测试服务器
场景 1:全库恢复
适合这种情况:
-
测试实例里没有重要数据
-
允许整体覆盖
-
目标就是把整批业务库恢复进去
如果备份文件已经去掉了系统库,比如:
all_no_mysql.sql
那恢复命令最简单:
mysql -P 3308 -u root -p < /soft/all_no_mysql.sql
恢复后检查:
mysql -P 3308 -u root -p -e "SHOW DATABASES;"
如果业务库都在,说明整体恢复基本成功。
场景 2:只恢复单库
这是更常见、也更稳的操作。
假设现在只想恢复 demo_app 这个库。
第一步:先创建目标库(字符集和源库一致)
mysql -P 3308 -u root -p -e "CREATE DATABASE IF NOT EXISTS \`demo_app\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
这里要注意:
-
库名要和你要恢复的库名一致
-
字符集、排序规则尽量和源库保持一致
第二步:执行单库恢复
mysql --one-database demo_app -P 3308 -u root -p < /soft/all_no_mysql.sql
第三步:恢复后检查
mysql -P 3308 -u root -p -e "SHOW TABLES FROM \`demo_app\`;"
如果表都出来了,单库恢复就基本完成了。
三、恢复到源库
这里要先讲一句实话:
源库恢复比测试服务器恢复危险得多。
因为一旦操作不对,容易覆盖现有数据。
所以恢复到源库前,建议先再备份一次当前库,留退路。
场景 1:源库全库恢复
这种情况一般只在明确要整体回退时才做。
如果你确认要整体恢复业务库:
mysql -u root -p < /data/backup/mysql/all_no_mysql.sql
如果是原始整包备份文件,也可以:
mysql -u root -p < /data/backup/mysql/all_2026-03-28_09-51-25.sql
但这类操作风险最大,不建议随便做。
场景 2:源库单库恢复
这是生产上更常见、更稳妥的方式。
假设要恢复 demo_app。
第一步:删除旧库
如果确认要覆盖原库,先删旧库:
mysql -u root -p -e "DROP DATABASE IF EXISTS \`demo_app\`;"
第二步:重新建库
建库时字符集和排序规则尽量与原库一致:
mysql -u root -p -e "CREATE DATABASE \`demo_app\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
第三步:恢复单库
mysql --one-database demo_app -u root -p < /data/backup/mysql/all_no_mysql.sql
第四步:检查恢复结果
mysql -u root -p -e "SHOW TABLES FROM \`demo_app\`;"
四、为什么单库恢复必须先建库
这是恢复单库时最关键的细节。
mysql --one-database 库名 的作用,不是"自动把这个库恢复出来",而是:
只执行 SQL 文件中属于这个库的语句。
也就是说,它只是"过滤执行",不是"自动建库"。
它不是按文件名识别,也不是按表名猜,而是按 SQL 文件里的 USE 库名 来判断哪些语句该执行。
所以如果目标库不存在,它一开始就会失败。
这就是为什么:
-
全库恢复 通常不需要手工建库
-
单库恢复 通常必须先建好库
因为全库恢复的 SQL 文件里一般自带:
CREATE DATABASE ...
USE ...
而单库恢复时你用的是 --one-database 过滤执行,目标库得先存在。
五、为什么不建议备份时带系统库
实际恢复过程中,最麻烦的地方往往就是系统库。
如果备份文件里带了 mysql 系统库,恢复到测试服务器时可能会带来这些问题:
-
修改测试实例的 root 密码
-
覆盖用户和权限
-
恢复过程中更容易出错
-
单库恢复时处理更麻烦
所以更推荐的做法是:
1. 如果只是业务恢复,导出时就不要带系统库
不要再用:
mysqldump --all-databases
更推荐:
mysqldump -uroot -p \
--databases \
demo_app demo_order demo_report \
--routines --events --triggers \
--single-transaction --quick --hex-blob \
--default-character-set=utf8mb4 \
> business_all.sql
这样导出来的文件只包含业务库,不包含 mysql 系统库。
2. 如果以后经常只恢复单库,最好直接做单库备份
mysqldump -uroot -p \
--databases demo_app \
--routines --events --triggers \
--single-transaction --quick --hex-blob \
--default-character-set=utf8mb4 \
> demo_app.sql
这样以后恢复最简单:
mysql -u root -p < demo_app.sql
六、恢复完成后,源库和测试库可以对比什么
恢复完成后,建议至少对比以下几个维度:
-
库是否存在
-
每个业务库有多少张表
-
某个库里有哪些表
-
核心表有多少行数据
-
字符集和排序规则是否一致
1. 对比有哪些库
SHOW DATABASES;
如果只想看业务库,不看系统库,可以用:
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name NOT IN ('mysql','information_schema','performance_schema','sys')
ORDER BY schema_name;
2. 对比每个业务库有多少张表
SELECT table_schema, COUNT(*) AS table_cnt
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
GROUP BY table_schema
ORDER BY table_cnt DESC;
这条 SQL 很实用,能快速看出:
-
哪些库恢复进来了
-
每个库有多少张表
-
源库和测试库表数量是否一致
3. 对比某个库里有哪些表
例如查看 demo_app:
SHOW TABLES FROM `demo_app`;
或者:
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'demo_app'
ORDER BY table_name;
4. 对比某个库里有多少张表
SELECT COUNT(*) AS table_cnt
FROM information_schema.tables
WHERE table_schema = 'demo_app';
5. 对比核心表的行数
例如对比 users 表和 orders 表:
SELECT COUNT(*) AS row_cnt FROM demo_app.users;
SELECT COUNT(*) AS row_cnt FROM demo_app.orders;
源库执行一次,测试库执行一次,直接比结果。
说明一下:
如果表很多,不建议一上来每张表都 COUNT(*) ,太重。
实际工作中一般抽查:
-
主业务表
-
大表
-
关键配置表
-
最近变更过的表
这样就够用了。
6. 快速看某个库里每张表的大概行数
SELECT table_name, table_rows
FROM information_schema.tables
WHERE table_schema = 'demo_app'
ORDER BY table_rows DESC;
这个更快,但要注意:
对于 InnoDB 表,这个行数通常是估算值,不一定绝对准确。
如果要精确对比,还是以 COUNT(*) 为准。
7. 对比字符集和排序规则
SELECT schema_name, default_character_set_name, default_collation_name
FROM information_schema.schemata
WHERE schema_name = 'demo_app';
主要对比:
-
default_character_set_name -
default_collation_name
如果源库和测试库不一致,恢复后可能会有乱码、排序差异等问题。
七、以后可以直接照着用的命令
测试服务器全库恢复
mysql -P 3308 -u root -p < /soft/all_no_mysql.sql
测试服务器单库恢复
mysql -P 3308 -u root -p -e "CREATE DATABASE IF NOT EXISTS \`demo_app\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
mysql --one-database demo_app -P 3308 -u root -p < /soft/all_no_mysql.sql
源库全库恢复
mysql -u root -p < /data/backup/mysql/all_no_mysql.sql
源库单库恢复
mysql -u root -p -e "DROP DATABASE IF EXISTS \`demo_app\`;"
mysql -u root -p -e "CREATE DATABASE \`demo_app\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
mysql --one-database demo_app -u root -p < /data/backup/mysql/all_no_mysql.sql
八、总结
MySQL 逻辑备份恢复,命令其实不复杂,真正要记住的是流程和细节:
-
恢复前先对比字符集、排序规则
-
恢复到测试服务器和恢复到源库要分开看
-
全库恢复可以直接导
-
单库恢复一定记得先建库
-
备份时尽量不要把系统库一起带进去
-
恢复完成后,要核对库、表、表数量和核心表数据量
一句话收尾:
全库恢复靠整体导入,单库恢复靠先建库再过滤恢复。
如果你后面想把这篇再改成更像"运维经验总结"的风格,我也可以继续帮你润成更适合发博客的版本。