升级MySQL跨大版本必须显式导出mysql系统库,因mysqldump --all-databases默认不导出;导入前需启用skip-grant-tables,导入后执行mysqld --upgrade修正表结构与密码哈希,再重启并验证真实业务操作权限。

升级前必须导出 mysql 库,不能只靠 mysqldump --all-databases
MySQL 升级(尤其是跨大版本,如 5.7 → 8.0)时,mysqldump --all-databases 默认**不会导出 mysql 系统库**,因为它的表结构和权限模型可能不兼容。直接跳过会导致所有用户、角色、密码策略、存储过程权限丢失。
正确做法是显式导出 mysql 库,并注意以下几点:
-
mysqldump必须用具有SELECT权限的高权限账号(如root),且需加--skip-triggers(避免触发器执行失败干扰导出) - 必须加上
--single-transaction(对 InnoDB 有效)或--lock-all-tables(兼容 MyISAM),否则导出过程中权限变更可能被遗漏 - 务必排除
sys库(它是只读视图集合,新版自动生成,导入会报错):用--ignore-table=mysql.sys - 示例命令:
mysqldump -u root -p --single-transaction --routines --events --ignore-table=mysql.sys mysql > mysql_system_backup.sql
导入 mysql 库前要停掉新实例的权限校验
MySQL 8.0+ 启动后默认启用严格权限校验(如 skip_grant_tables=OFF),此时直接执行 source mysql_system_backup.sql 会因密码哈希格式、字段缺失(如 password_expired)、默认角色字段报错。
安全导入流程如下:
- 启动新 MySQL 实例时临时加配置:
skip-grant-tables+skip-networking(防止未授权访问) - 连接后先执行
FLUSH PRIVILEGES;,再用source mysql_system_backup.sql - 导入完成后,**必须手动执行
mysql_upgrade(8.0.16 之后已废弃,改用mysqld --upgrade)**,它会修正系统表结构、更新密码哈希、补全缺失字段 - 最后重启服务,移除
skip-grant-tables
mysql.user 表字段变化是权限丢失的主因
MySQL 5.7 和 8.0 的 mysql.user 表字段差异极大,比如:
- 5.7 用
Password字段存哈希;8.0 改为authentication_string,且默认使用caching_sha2_password插件 - 8.0 新增
account_locked、password_last_changed、password_reuse_history等字段,旧备份里没有这些列 - 直接导入会导致 INSERT 失败或字段被截断,进而使用户无法登录
应对方式不是手动删字段,而是依赖 mysql_upgrade 或 mysqld --upgrade 自动补全并转换——它会读取备份中的旧哈希,按新规则重写到对应字段,同时设置合理默认值。
升级后验证权限不能只看 SHOW GRANTS
SHOW GRANTS FOR 'user'@'host' 显示正常,不代表权限真正生效。常见漏检点:
- 角色(
ROLE)是否被正确激活?检查SELECT * FROM mysql.role_edges; - 动态权限(如
BACKUP_ADMIN)在 8.0 才引入,5.7 备份中无记录,需手工补授 - 数据库/表级权限是否因大小写敏感(
lower_case_table_names配置不一致)导致匹配失败? - 插件认证是否匹配?例如从 5.7 升级后用户仍用
mysql_native_password,但服务器默认要求caching_sha2_password,需显式修改:ALTER USER 'user'@'host' IDENTIFIED WITH mysql_native_password BY 'pwd';
最稳妥的验证方式:用目标用户连接,执行原业务中真实依赖的 DML/DCL 操作(如创建临时表、调用特定函数、访问特定视图),而非仅查权限元数据。


















