mysql 5.7升级到8.0后启动失败报“table 'mysql.user' doesn't exist”,根本原因是旧myisam系统表未迁移至innodb+数据字典结构,需用mysqld --upgrade=force强制触发内核级元数据重构,而非执行已废弃的mysql_upgrade。

MySQL 5.7 升级到 8.0 后启动失败,报错 Table 'mysql.user' doesn't exist 或 Can't open and lock privilege tables,基本可以确定是系统表未完成迁移——8.0 彻底弃用 MyISAM 系统表,全部转为 InnoDB + 数据字典结构,旧数据目录直接复用会导致核心元数据缺失,服务根本起不来。
启动失败时先看错误日志里有没有“mysql.user doesn’t exist”
这不是权限配置问题,而是底层元数据结构断裂。8.0 启动时会校验 mysql 库下所有系统表是否符合新格式(如 mysql.user 实际由 mysql.global_grants、mysql.role_edges 等支撑),若仍残留 5.7 的 MyISAM 表或字段不全,就会拒绝加载。
- 立刻查错误日志:运行
sudo tail -n 50 /var/log/mysqld.log或根据mysqld --help --verbose | grep "log-error"找到真实路径 - 关键线索包括:
Table 'mysql.plugin' doesn't exist、InnoDB: The system tablespace must be writable、Unknown table 'performance_schema.session_variables' - 别信“配置文件写错了”——这类报错 90% 以上是数据目录没升级到位,不是
my.cnf有问题
必须用升级后版本的 mysqld --upgrade=FORCE 启动初始化
mysql_upgrade 在 8.0 中已废弃,它不再适用;真正起作用的是 mysqld 自身的自动升级逻辑,但必须显式触发。
- 停止所有 MySQL 进程:
sudo systemctl stop mysql(或killall mysqld) - 确保
datadir所有者是mysql:mysql:sudo chown -R mysql:mysql /var/lib/mysql - 用 8.0 的
mysqld二进制强制升级:/usr/local/mysql-8.0/bin/mysqld --datadir=/var/lib/mysql --upgrade=FORCE --user=mysql - 注意:路径必须准确,不能调用旧版
mysqld;Docker 用户要确认容器内执行的是镜像自带二进制,不是挂载进来的旧版
如果 --upgrade=FORCE 报错卡在 performance_schema 或 innodb_index_stats
说明升级中途被中断,或权限/磁盘空间不足,导致部分系统表重建失败。此时不能重试,否则状态更糟。
- 检查磁盘剩余空间:
df -h /var/lib/mysql,至少留 2GB 空闲 - 确认
mysql用户对datadir有完整读写权限,尤其ibdata1和mysql.ibd - 查看日志末尾 ERROR 行,例如
ERROR 1878 (HY000)指向统计信息创建失败,常因innodb_file_per_table=OFF且旧表未迁移 - 临时方案:删掉
performance_schema目录(仅限测试环境),重启后 8.0 会自动重建;生产环境应重做就地升级,而非修补
启动成功后第一件事:验证 mysql.user 是否为视图且字段完整
登录后立刻执行:SELECT User, Host, plugin, authentication_string FROM mysql.user LIMIT 1;
- 如果报错
Unknown column 'authentication_string'或返回空,说明--upgrade=FORCE没生效或中途失败 - 正确结果中
plugin应为caching_sha2_password或mysql_native_password,authentication_string不为空 - 注意:
mysql.user在 8.0 是只读视图,不能UPDATE,只能用ALTER USER修改用户认证方式
最易被忽略的点是:很多人以为跑完 mysql_upgrade 就万事大吉,却没意识到 8.0 已弃用它,必须靠 mysqld --upgrade=FORCE 触发真正的元数据重构;而一旦升级中断,残留的半成品状态比完全没升级还难修复。











