MySQL 5.6 升级到 5.7 后系统表(如 mysql.user)仍为 MyISAM,这是官方设计而非遗漏;mysql_upgrade 不修改引擎,仅更新结构与内容;手动 ALTER 会导致启动失败、权限失效或复制中断;应优先转换业务表而非系统表。

MySQL 5.6 升级到 5.7 后,系统表(如 mysql 库下的 user、db、tables_priv 等)不会自动转为 InnoDB —— 它们仍保持 MyISAM 引擎,且 mysql_upgrade 不会修改引擎类型。 这不是遗漏,而是 MySQL 的明确设计:系统表引擎由服务器启动时硬编码决定,升级工具只更新结构和内容,不触碰引擎。强行 ALTER 会破坏一致性,甚至导致服务无法启动。
为什么不能对 mysql.user 等系统表执行 ALTER TABLE ENGINE=InnoDB
MySQL 5.7 的系统表在初始化或 mysql_upgrade 时由服务器内部逻辑创建,其引擎是写死的(5.7 默认用 MyISAM 存储系统表,直到 8.0 才全面切换为 InnoDB)。手动执行 ALTER TABLE mysql.user ENGINE=InnoDB 会触发以下问题:
- 启动失败:mysqld 检测到系统表引擎不匹配预期,拒绝加载
- 权限失效:即使侥幸启动,
SELECT或GRANT可能报错Table 'mysql.user' doesn't exist(因元数据缓存与物理引擎不一致) - 复制中断:从库回放该 DDL 时直接 crash,因为从库同样校验系统表引擎
mysql_upgrade 实际做了什么(以及它没做什么)
mysql_upgrade 的核心任务是比对当前数据字典版本与目标版本(5.7)所需的结构,然后执行必要变更,例如:
- 添加缺失字段(如
mysql.user新增password_last_changed) - 重建视图(如
INFORMATION_SCHEMA相关视图) - 更新
mysql.help_topic等只读表内容 - 但绝不修改
ENGINE、ROW_FORMAT或索引类型等物理属性
你执行 mysql_upgrade -u root -p --force 后看到的 OK 提示,只代表结构同步完成,不代表引擎已变。可验证:SELECT table_name, engine FROM information_schema.tables WHERE table_schema='mysql' AND table_name IN ('user','db','procs_priv'); 结果仍是 MyISAM。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
真正需要转换的其实是业务表,不是系统表
如果你的目标是“让所有表都用 InnoDB”,重点应放在业务库,而非 mysql 库。系统表保留 MyISAM 在 5.7 中完全合法、稳定且被官方支持。实际风险点反而是那些长期未维护的业务 MyISAM 表:
- 它们不支持事务、行锁、外键,升级后若业务逻辑依赖这些特性,会出隐性 Bug
- 5.7 对 MyISAM 的优化极少,性能瓶颈更明显
- 未来若计划升 8.0,MyISAM 表需先转 InnoDB(8.0 虽仍支持,但已标记为 deprecated)
所以请用这个命令拉出待处理清单:SELECT CONCAT('ALTER TABLE `', table_schema, '`.`', table_name, '` ENGINE=InnoDB;') AS ddl FROM information_schema.tables WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys') AND engine = 'MyISAM'; —— 然后对结果中的业务表逐个或批量执行(注意加 LOCK=NONE 和 ALGORITHM=INPLACE,前提是 MySQL ≥5.6 且无 FULLTEXT 索引)。
系统表引擎这件事,不是“能不能做”,而是“没必要做,也不该做”。真正容易被忽略的是:很多人升级完只盯着 mysql_upgrade 成功与否,却没检查业务表是否还在用 MyISAM——那才是后续故障的温床。

















