多租户下按 Schema 备份必须用 mysqldump 显式指定库名,禁用 --all-databases;恢复时须提前创建目标库并显式指定库名,否则数据错位或报错。

直接结论:多租户下按 Schema(即独立数据库)备份,必须用 mysqldump 显式指定数据库名,不能依赖 --all-databases 或通配符;恢复时必须提前创建目标库并显式指定库名,否则数据会写错位置或报错。
为什么不能用 --all-databases 备份单个租户 Schema
虽然 mysqldump -u root -p --all-databases 会导出所有库,但问题在于:--all-databases 生成的 SQL 文件里每个 CREATE DATABASE 和 USE 语句都带完整库名,且顺序不可控。一旦租户库名含特殊字符(如连字符、下划线开头)、或存在系统库(mysql、information_schema),恢复时可能意外覆盖权限表或跳过目标库。
更关键的是:你无法在恢复阶段“只取其中某一段”,因为整个文件是一体执行的。实际中曾有团队误将 --all-databases 备份用于单租户恢复,结果把 mysql.user 表也重刷了,导致所有账号失效。
正确做法是为每个租户单独备份:
mysqldump -u backup_user -p --single-transaction --routines --triggers tenant_a > /backup/tenant_a_$(date +%F).sql- 务必加
--single-transaction(对 InnoDB 保证一致性),不加则可能遇到锁表或数据不一致 - 避免使用 root 账号备份,应建专用账号并只授予
SELECT、LOCK TABLES、SHOW VIEW、TRIGGER权限
mysql 命令恢复时必须显式指定数据库名
这是最容易踩的坑。很多人备份完 tenant_b,恢复时只写:
mysql -u root -p < /backup/tenant_b_2026-09-03.sql
结果报错:ERROR 1046 (3D000): No database selected —— 因为 dump 文件里没有 USE tenant_b,或该语句被注释掉了(尤其用 --no-create-info 时)。
真正安全的恢复命令是:
-
mysql -u root -p tenant_b < /backup/tenant_b_2026-09-03.sql(推荐) - 或先登录后执行:
mysql -u root -p→use tenant_b;→source /backup/tenant_b_2026-09-03.sql; - 切勿在没
USE的前提下直接导入,否则CREATE TABLE会建在默认库(通常是test)里
租户名动态化备份脚本的关键校验点
自动化脚本常因租户名拼接出错导致备份空文件或错库。例如用 for db in $(mysql -Nse "show databases like 'tenant_%'") 获取库名,但若库名含空格或破折号,循环会断裂。
安全写法需加引号和转义:
- 用
mysql -N -s -e "SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE 'tenant\_%'"(双反斜杠防 MySQL 解析) - 每次 dump 前检查库是否存在:
mysql -Nse "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '$db'" | grep -q "$db" - dump 后立刻验证行数:
grep -c "^INSERT INTO" "/backup/${db}_$(date +%F).sql" || echo "WARN: no data in $db backup"
另外,压缩备份(mysqldump ... | gzip)虽省空间,但恢复前必须解压——线上脚本若忘记 gunzip -c 就直接 pipe 给 mysql,会静默失败且无报错。
跨环境恢复时字符集与排序规则要对齐
租户 A 在生产库用 utf8mb4_unicode_ci,备份恢复到测试库时若目标库是 utf8mb4_general_ci,某些 emoji 或生僻字插入会报错 Incorrect string value,但表结构仍能建成功,数据截断不易察觉。
解决方案:
- 备份时显式指定字符集:
mysqldump --default-character-set=utf8mb4 -u ... - 恢复前确认目标库编码:
mysql -e "SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='tenant_c';" - 必要时重建库:
DROP DATABASE tenant_c; CREATE DATABASE tenant_c CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
最后提醒:Schema 级多租户的备份粒度就是库,不存在“只备份 tenant_d 的某几张表还保持租户隔离”的安全做法——一旦混用表级备份,就等于打破 Schema 边界,后续权限、监控、成本分摊都会失控。


















