
加密表空间迁移时 keyring 文件不一致会直接报错
MySQL 加密表空间(如 innodb_encrypt_tables=ON)依赖 keyring 插件管理主密钥,而密钥本身不存于数据库内,而是落在文件系统中(比如 keyring_file_data 指向的 JSON 文件)。迁移表空间文件(.ibd)时,如果目标实例没加载相同的 keyring 文件、或文件内容被修改 / 覆盖,启动时就会卡在 Tablespace is encrypted but no keyring is available 或类似错误,甚至直接拒绝挂载该表。
必须同步 keyring_file_data 文件且确保权限和路径一致
keyring 文件不是“备份后拷过去就行”,它对路径、属主、权限极其敏感。MySQL 启动时会校验文件是否可读、是否被篡改(内部有 checksum)、是否与当前 keyring 插件版本兼容。
-
keyring_file_data路径需完全一致:比如源库是/var/lib/mysql-keyring/keyring,目标库配置里也得是这个绝对路径,不能只复制文件到别的位置然后改配置——MySQL 会拒绝加载非预期路径下的 keyring - 文件权限必须是
600,属主必须是运行 mysqld 的用户(通常是mysql:mysql),否则插件初始化失败,日志里出现Failed to load keyring file: Permission denied - 不要用文本编辑器手动修改 keyring 文件:JSON 结构易出错,且 MySQL 内部会对 keyring 文件做哈希校验;哪怕只多一个空格,重启后也会提示
Keyring file is corrupted - 若源库用了
keyring_encrypted_file(AES 加密的 keyring),你还得一并迁移它的密码(通过keyring_encrypted_file_password配置项传入),且该密码不能丢失
迁移前必须停写并显式刷新加密表空间
表空间加密状态是动态的,某些页可能缓存在 buffer pool 中未落盘。直接拷贝 .ibd 文件可能导致页加密状态不一致,恢复后查询时报 Encrypted tablespace page decryption failed。
- 执行
FLUSH TABLES tbl_name FOR EXPORT(适用于单表迁移),或全局停写后FLUSH TABLES WITH READ LOCK+FLUSH ENGINE LOGS - 确认
INFORMATION_SCHEMA.INNODB_TABLESPACES中对应表的ENCRYPTION字段为Y,且STATE是active,避免误迁未加密副本 - 拷贝前检查
.ibd文件大小是否稳定(无写入时大小应不再增长),防止截断
目标实例启动前要验证 keyring 插件加载顺序和参数
MySQL 加载 keyring 插件有严格顺序:必须在 InnoDB 初始化之前完成。配置错位会导致插件加载成功但不生效,表空间解密失败却无明显报错。
- 在
my.cnf中,early-plugin-load=keyring_file.so必须出现在[mysqld]段最开头,不能放在其他插件之后 -
keyring_file_data必须是绝对路径,且不能和datadir在同一磁盘分区(官方建议,避免崩溃时 keyring 和数据同时损坏) - 启动后立刻查
SELECT * FROM performance_schema.keyring_keys;,确认密钥数量、名称、type 和源库一致;如果为空,说明 keyring 没真正加载成功 - 别跳过
ALTER TABLE tbl_name IMPORT TABLESPACE步骤——即使表结构已存在,也必须走这个流程触发 InnoDB 对加密元数据的校验
最常被忽略的是 keyring 文件的属主和 SELinux 上下文(如果开了 SELinux)。哪怕所有配置都对,ls -Z 一看发现 keyring 文件上下文是 unconfined_u:object_r:user_home_t:s0,而 mysqld 只能读 system_u:object_r:mysqld_db_t:s0,照样静默失败。这事没法靠日志一眼看出,得盯住 audit.log 或临时关 SELinux 排查。