mysql 5.7→8.0跨大版本升级不能在主库直接执行mysql_upgrade或替换二进制,因需独占访问系统库,否则导致主库写入阻塞、从库sql线程卡死、gtid不一致、认证插件不匹配及连接池重连失败。

大流量环境下不能停服,MySQL内核版本滚动升级唯一可行路径是主从复制架构下的分节点替换,不是“替换二进制再重启”那种原地操作。
为什么不能直接在主库上执行 mysql_upgrade 或替换二进制?
因为 MySQL 5.7 → 8.0 这类跨大版本升级会触发数据字典重构、系统表结构变更、默认认证插件切换(mysql_native_password → caching_sha2_password),这些操作需要独占访问 mysql 系统库。一旦在主库上执行,会导致:
- 主库写入阻塞数分钟甚至更久(尤其当系统表多、元数据大时)
- 从库 SQL 线程卡住,复制延迟飙升,可能触发 GTID 不一致或
ERROR 1236 - 连接池持续重连失败,应用层出现大量
Access denied for user或Unknown authentication plugin
滚动升级必须满足的三个前置条件
缺一不可,否则所谓“滚动”只是把风险延后爆发:
- 主从拓扑必须是 GTID 模式(
gtid_mode=ON),且所有节点enforce_gtid_consistency=ON;否则无法安全切换主从角色 - 所有业务 SQL 必须兼容 MySQL 8.0 严格模式(例如禁用隐式
GROUP BY、不依赖query_cache、不使用已移除的OLD_PASSWORD()函数) - 客户端驱动必须支持目标版本:JDBC 需 ≥ 8.0.28,Python
mysql-connector-python需 ≥ 8.0.33,否则握手阶段就报Authentication plugin 'caching_sha2_password' cannot be loaded
实际执行时最关键的三步操作顺序
顺序错一步,整个滚动过程就会卡死或数据不一致:
- 先在空闲从节点上部署新版本 MySQL 8.0,用
mysqld --initialize-insecure初始化,然后配置为基于 GTID 的从库(CHANGE MASTER TO ... GET_MASTER_PUBLIC_KEY=1),启动复制并确认Seconds_Behind_Master = 0且无错误 - 对该新节点执行
mysql_upgrade -u root -p --force(仅此节点需运行),完成后立即执行ANALYZE TABLE mysql.*更新统计信息,避免优化器误判 - 执行主从切换:先
STOP SLAVE在旧主,再RESET SLAVE ALL;在新 8.0 节点上执行STOP SLAVE; RESET MASTER;,最后用SELECT MASTER_POS_WAIT(...)确认所有 binlog 已消费完毕,才SET GLOBAL read_only=OFF并将流量切过去
升级后最容易被忽略的五个细节
它们不会导致启动失败,但会在高并发下突然引发雪崩:
-
innodb_buffer_pool_size值不能照搬旧配置——MySQL 8.0 默认启用innodb_dedicated_server,会自动计算该值;若手动设死,反而导致内存争抢 - 所有用户密码需显式重建:
ALTER USER 'xxx'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd';,否则 JDBC 连接池会因插件不匹配反复重试 - 慢查询日志格式变了,
log_output='TABLE'时,mysql.slow_log表结构已更新,旧解析脚本会字段错位 -
performance_schema默认全开,若没调大performance_schema_max_table_instances,高并发下会频繁报Could not allocate table instance - 字符集迁移未完成:即使数据库和表已是
utf8mb4,也要检查information_schema.COLUMNS中character_set_name是否全为utf8mb4,否则 JSON 字段存 Emoji 会截断











