MySQL 5.6 与 8.0 之间的差异是跨越式的,中间还隔了一个重要的 5.7 版本,8.0 并非 5.6 的简单增强,而是在架构设计、SQL 标准支持、安全模型和性能优化上都进行了重构
1.核心差异总览
| 对比维度 | MySQL 5.6 | MySQL 8.0 |
|---|---|---|
| SQL 功能 | 基础 SQL,不支持窗口函数、CTE | 支持窗口函数、CTE、角色,JSON 功能增强 |
| 数据字典 | 元数据存储于文件和非事务表中,非原子 | 事务性数据字典,元数据存储在 InnoDB 中,支持原子 DDL |
| 默认字符集 | latin1 or utf8(utf8mb3) | utf8mb4 |
| 查询缓存 | 存在(默认禁用) | 已彻底移除 |
| 索引特性 | 不支持降序索引(DESC被忽略) | 支持降序索引、不可见索引 |
| 复制与高可用 | 基于 GTID 的复制(较新特性) | 增强的复制功能,支持异步连接故障转移 |
| 安全性 | mysql_native_password为默认认证插件 | caching_sha2_password为默认,引入角色和动态权限 |
| InnoDB 优化 | 基础 InnoDB 功能 | 大量并发优化,如分拆 kernel mutex、flush 操作分离 |
2. SQL 语法与功能增强
窗口函数 (Window Functions):5.6 不支持, 8.0 引入了完整的窗口函数(如
ROW_NUMBER(),RANK(),LEAD(),LAG()),使得在查询中直接进行复杂的排名、移动平均和同比/环比分析成为可能,无需再依赖自连接或复杂的子查询公用表表达式 (CTE):5.6 不支持,8.0 支持
WITH子句,包括递归 CTE,这极大地简化了层级数据(如组织架构树、分类目录)的查询和复杂子查询的编写,使 SQL 逻辑更清晰JSON 支持:5.6 对 JSON 的支持非常有限,8.0 提供了原生的 JSON 数据类型和丰富的函数(如
JSON_TABLE),可以直接将 JSON 数据当作关系表来查询,大大提升了处理半结构化数据的效率
3.架构与性能优化
数据字典与原子 DDL:5.6 的元数据存储在文件和非事务性表中,DDL 操作不具备原子性,8.0 引入了事务性数据字典,将所有元数据存储在 InnoDB 表中,这直接带来了原子 DDL:一个 DDL 操作要么完全成功,要么完全失败,不会出现中间状态,极大提升了数据库在崩溃时的安全性和可靠性
查询缓存移除:5.6 中查询缓存已默认禁用,且在高并发场景下容易成为瓶颈,8.0 得益于更高效的编解码器、自适应哈希索引优化以及查询缓存的移除,消除了这一性能瓶颈,将优化重心放在了更高效的执行计划和索引上
InnoDB 引擎优化:8.0 对 InnoDB 进行了大量底层优化,例如分拆 kernel mutex、将 flush 操作从主线程分离等,旨在提升高并发场景下的可扩展性和吞吐量
DDL 算法演进:MySQL 5.5 执行 DDL(如加字段、加索引)时仅支持
COPY算法,期间表完全只读;MySQL 8.0 引入了INSTANT算法,对于部分 DDL 操作仅需修改元数据,可实现秒级完成,显著降低了对业务的影响- 索引大小限制:MySQL 8.0 默认索引大小上限提升至 3072 字节,允许组合索引包含更多的列,而 5.5 的上限仅为 1000 字节
4.安全性与权限管理
认证插件:5.6 使用
mysql_native_password, 8.0 将caching_sha2_password作为默认认证插件,提供了更强的密码加密和缓存机制角色 (Roles):5.6 不支持角色概念, 8.0 引入了角色管理,可以创建角色并为其授予权限,然后将角色授予用户, 这极大简化了批量用户的权限管理,是 5.6 所不具备的重要企业级功能
5.复制与高可用性
故障转移:5.6 的复制故障转移需要手动或借助外部工具,8.0 增强了对GTID(全局事务标识符)的支持,并引入了异步连接故障转移机制, 当主库失效时,从库可以自动连接到新的主库,提升了复制拓扑的自动化恢复能力。
6. 索引新特性
降序索引:在 5.6 中,索引定义里的
DESC关键字会被忽略,索引始终按升序存储, 8.0 开始真正支持降序索引,对于需要按降序排序的查询(如获取最新记录),可以显著提升性能不可见索引:8.0 支持将索引标记为“不可见”, 优化器会忽略该索引,但索引本身仍会被维护, 这为评估删除索引的影响提供了安全的“后悔药”,可以先隐藏索引观察性能,确认无影响后再删除
- 自增变量持久化:MySQL 8.0 解决了历史遗留问题,对
AUTO_INCREMENT值进行了持久化,数据库重启后不会重置;而 5.5 在重启后可能会重置自增主键,导致潜在的主键冲突3。- 生命周期:MySQL 5.5 已于 2018 年 12 月正式停止官方支持(EOL),不再提供安全补丁;MySQL 8.0 则是当前企业级应用的主流选择,享有长期的官方维护与云原生架构支持
7.升级注意事项
从 5.6 升级到 8.0不能直接跳级,必须遵循5.6 → 5.7 → 8.0的路径,升级前需要重点检查:
认证插件:应用使用的驱动可能不支持 8.0 默认的
caching_sha2_password,可能需要调整或升级驱动SQL 兼容性:5.7 中被废弃的语法或功能(如
GROUP BY的隐式排序)在 8.0 中已被移除,需要修改应用 SQL配置参数:许多在 5.6/5.7 中被忽略的无效配置项,在 8.0 启动时会直接导致错误,需要清理配置文件
(1).动手前先确认三件
| 检查项 | 说明 |
|---|---|
| 具体小版本号 | SELECT VERSION();—— 若低于 5.6.40,建议先在 5.6 内升到该系列最新版再走后续流程,减少已知 bug |
| 操作系统能否跑 8.0 | 官方 8.0 二进制要求 glibc ≥ 2.17,即 CentOS/RHEL 6 无法直接运行 8.0(需换 OS 或用厂商定制包)。这一步常导致“数据迁完了实例起不来” |
| 是否开了GTID / 半同步 / MGR 前身架构 | 5.6 的 GTID 有硬限制(见下文 B-9),会影响升级路径设计 |
(2).兼容性问题清单
A 类:不改就起不来 / 连不上
A-1|配置文件残留废弃参数(实例拒绝启动)
5.6 能用而 8.0 彻底移除的典型项:
query_cache_type / query_cache_size / query_cache_limit # 查询缓存整块移除 innodb_file_format / innodb_file_format_check / innodb_file_format_max innodb_large_prefix # 8.0 恒为 ON innodb_locks_unsafe_for_binlog old_passwords log-slow-queries / slow_query_log 的旧写法 enable-partition # 分区插件不再可禁用 NO_AUTO_CREATE_USER # sql_mode 中此值已不存在做法:用 8.0 二进制在测试环境试启动,按
unknown variable报错逐项清理,不要直接复用老 cnf
A-2|认证插件变更 → 老客户端连不上
8.0 默认
caching_sha2_password,5.6 时代全是mysql_native_password, 老驱动会报Authentication plugin 'caching_sha2_password' cannot be loaded,
做法(优先级从高到低):
- ① 升级驱动(JDBC 8.0.x、Python 换 mysqlclient/pymysql 新版、PHP 用 mysqlnd)
- ② 账号级改回
mysql_native_password- ③ 全局设
default_authentication_plugin=mysql_native_password(仅过渡),同时注意 8.0 默认 TLS 策略更严,老客户端握手失败需检查tls_version
A-3|lower_case_table_names初始化后不可改
8.0 在
--initialize时固化该值,改了就拒绝启动,Linux 上 5.6 若是 1,8.0 也必须 1,做法:升级前记录原值,新实例初始化时显式指定
A-4|密码过期导致某天全线 Access denied
5.6 无密码过期机制,迁到 8.0 后可能命中
default_password_lifetime=180(8.0.28 后改为0)
做法:迁移后立即执行ALTER USER ... PASSWORD EXPIRE NEVER
A-5|权限不能靠拷mysql库迁移
5.6 的
mysql.user还有Password字段,5.7 改为authentication_string,8.0 是事务型数据字典,直接拷贝必挂
做法:用 Percona 工具导出授权语句并在新库重放
pt-show-grants -h 5.6-host -u root -p > grants.sql # 检查输出里有没有 PASSWORD('...') 形式的旧哈希,有则说明存在 4.1 前旧密码,需重置A-6|物理备份工具版本必须匹配目标版本
XtraBackup 2.3 对应 5.6,2.4 对应 5.7,8.0 系列对应 8.0,不能用 5.6 的备份直接恢复到 8.0,mysqldump 建议用目标版本的二进制执行
A-7|mysql_upgrade的生命周期
5.6→5.7 每级升完必须手动执行
mysql_upgrade --upgrade-system-tables,到 8.0 这一步由服务端首次启动自动完成数据字典升级,8.0 里已没有这个命令,别在文档里留着它
B 类:能跑,但结果错 / 性能崩
B-1|sql_mode从宽松变严格(最大隐性杀手)
- 5.6 默认基本只有
NO_ENGINE_SUBSTITUTION- 8.0 默认:
ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION- 典型报错:
Expression ... not in GROUP BY clause、Incorrect datetime value: '0000-00-00'、Data too long、除零错误、字段无默认值插入失败- 做法:在测试环境开全量严格模式跑回归,优先修 SQL;工期不够可临时放宽,但要记入技术债清单
B-2|保留字冲突(语法报错 1064)
8.0 新增保留字命中老库对象名会直接报错:
ROWS, SYSTEM, RANK, DENSE_RANK, CUBE, ROLLUP, RECURSIVE, JSON_TABLE, MEMBER, EXCEPT, LATERAL, WINDOW, GENERATED, VIRTUAL, STORED, ENFORCED, CHECK等
做法:对照官方保留字表全量扫描 schema,加反引号或改名
B-3|CHECK 约束从“注释”变“强制”
5.6 解析但不校验 CHECK,库里可能已有脏数据;8.0 会强制执行,且存量脏数据会导致约束添加失败
做法:升级前先SELECT ... WHERE NOT(条件)扫脏数据,清洗后再加约束
B-4|字符集与排序规则连环坑
- 5.6 默认 latin1,8.0 默认utf8mb4;注意 8.0 中
utf8是utf8mb3的别名且会被标记为 deprecated- 转 utf8mb4 后索引前缀可能超 3072 字节上限 → 唯一索引重建失败
- 排序规则变为
utf8mb4_0900_ai_ci,同样的数据 ORDER BY 结果顺序会变,分页接口会出现重复/漏数据
做法:在线改字符集(大表用 pt-online-schema-change 或 gh-ost),业务层补确定性 ORDER BY,必要时显式指定 COLLATE
B-5|GROUP BY 隐式排序被移除
5.6 中
GROUP BY碰巧有序,8.0 不再保证,做法:有顺序要求的查询一律显式加ORDER BY
B-6|explicit_defaults_for_timestamp行为变化
5.6 默认 OFF(第一个 TIMESTAMP 列自动
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP且 NULL 可存);8.0 该参数默认 ON 且不允许再设为 OFF,迁移后 TIMESTAMP 列的默认值和 NULL 处理会变,需逐表核对
B-7|时间类型历史格式问题
5.6.4 之前创建的 TIME/DATETIME/TIMESTAMP 列使用旧内部格式,需通过
REPAIR TABLE/mysql_upgrade/ALTER TABLE ... FORCE重建,5.6 起点虽多为新格式,但若库是从更早版本升上来的,必须在 5.7 阶段用mysql_upgrade扫一遍
B-8|空间函数与非标语法
不带
ST_前缀的空间函数在 8.0 被移除;SRID 现在强制执行,空间索引要求列与索引 SRID 一致。GIS 业务需逐条核对
B-9|GTID 相关(5.6 特有)
5.6 的 GTID 不支持:非事务引擎表、事务内的
CREATE TEMPORARY TABLE、sql_slave_skip_counter,若计划在 8.0 用 GTID/MGR,需在 5.7 阶段先把这些隐患清掉(5.7 支持在线开启 GTID,可在不停机情况下切换)
B-10|复制参数与拓扑限制
- 只能低版本主 → 高版本从,且建议只跨一个大版本;8.0 从库不能挂 5.6 主库,这就是必须经 5.7 的原因
- 5.6 建议先切
binlog_format=ROW、binlog_row_image=FULL- 8.0.26+ 起
master/slave术语改为source/replica:rpl_semi_sync_master_*→rpl_semi_sync_source_*,SHOW SLAVE STATUS→SHOW REPLICA STATUS- 5.6 的
sync_master_info等参数名变动
B-11|执行计划回退
8.0 引入 Hash Join、直方图、降序索引、代价模型调整,同一 SQL 计划可能完全不同,做法:从 5.6 慢日志抓 Top SQL,在 8.0 测试库逐条
EXPLAIN FORMAT=TREE对比
B-12|监控/运维脚本集体失效
5.6 没有
sys库;8.0 的performance_schema表结构大变(setup_*表改名/合并)、INFORMATION_SCHEMA.INNODB_*字段变化、mysql_upgrade消失、mysql_install_db→mysqld --initialize、PASSWORD()函数被移除、SHOW PROFILES被移除、ENCODE/DECODE/DES_ENCRYPT 等函数移除,所有巡检、告警、备份脚本要逐条过
B-13|其他零散项
- 5.6 的
.par分区元数据文件在 8.0 取消(改用 InnoDB 原生分区 + 数据字典)- 8.0 内存占用更高,同等硬件需复核
innodb_buffer_pool_size、文件描述符、swap- 8.0 默认
innodb_undo_tablespaces=2,undo 独立表空间行为变化- X Plugin 默认监听 33060 端口,注意防火墙
- 同名索引在 8.0 中每张表内必须唯一(5.6 允许重复)
(3). 迁移步骤(Runbook)
阶段 0|评估与定型(1~2 周)
- 盘点:实例数、库表量、数据量、存储过程/触发器/事件/视图、定时任务、中间件与驱动版本、上下游同步链路
- 选路径:
- 数据量大 / 停机窗口短→ 逐级主从滚动(5.6 主 → 5.7 从 → 切主 → 8.0 从 → 切主)
- 数据量小(如 <200GB)/ 能接受较长停机→ 逻辑迁移一步到 8.0(跳过 5.7,但兼容性问题仍要在测试库验证)
- 定回滚方案:8.0 主库无法向 5.6 做从库,所以回滚只能“切回旧 5.6 主库 + 补偿增量”,必须在方案里写清决策点(超过 XX 分钟未成功即回滚)
- OS 与二进制就绪:确认 glibc/内核满足 8.0 要求,准备好 5.7 与 8.0 两套二进制及匹配版本的 xtrabackup
阶段 1|测试环境全量演练(2~4 周,最关键)
- 搭与生产同链路的测试环境,灌入脱敏真实数据子集(含最大表和最复杂业务场景)
- 完整走一遍升级,记录每步耗时、报错、手工操作
- SQL 基线:抓 Top 50~100 慢 SQL 逐条 EXPLAIN 对比,产出“是否回退/处理措施”表
- 全量回归:分页列表、聚合报表、金额计算、唯一键冲突路径、零日期/空值路径、批量导入、定时任务
- 压测 + 故障演练(主从延迟、断连重连、认证失败),并演练一次完整回滚
阶段 2|预修复(与业务并行)
- SQL 改造:GROUP BY/ORDER BY 补全、保留字加反引号、零日期清洗、非标函数替换
- 驱动与中间件升级:JDBC、连接池、ORM、分库分表/代理组件确认 8.0 兼容版本
- 权限重构:
pt-show-grants导出 → 清僵尸账号 → 按需引入 Role- 字符集整改(建议在 5.7 阶段完成,降低最终切换风险)
- 配置文件瘦身:剔除废弃项并加注释
阶段 3|正式迁移
路径一:逐级主从滚动(推荐)
1. 5.6 主库切 binlog_format=ROW,确认现有从库同步正常 2. 部署 5.7 从库(用 5.7 mysqldump 或 xtrabackup 2.4 建从),追平延迟,观察 1~3 天 3. 5.7 从库执行 mysql_upgrade;验证业务回归 4. 主从切换:5.7 升主,老 5.6 降为只读从库(保留!) (可选:此时对 5.7 跑 mysqlsh util.checkForServerUpgrade 预判 8.0 问题) 5. 部署 8.0 从库,追平延迟 6. 最终校验:pt-table-checksum 抽检核心表、行数/MAX(id)/金额汇总对账、 存储过程/视图/事件数量比对 7. 【停机窗口】停写 → 等完全追上 → 再校验 → 切流量到 8.0 8. 立刻跑冒烟用例 + 看核心接口 TP99;观察 24~72h 9. 旧库保留只读 3~7 天后下线路径二:逻辑迁移一步到 8.0
# 用 8.0 的 mysqldump 连接 5.6 导出 mysqldump -h src -u root -p \ --all-databases --single-transaction --triggers --routines --events \ --hex-blob --set-gtid-purged=OFF --max-allowed-packet=1G \ --default-character-set=utf8mb4 > full.sql # 导入 8.0 mysql -h dst -u root -p --max-allowed-packet=1G < full.sql # 导入后必做 ANALYZE TABLE <核心表>; # 统计信息重建,否则计划可能很差数据量大时改用mydumper/myloader(并行,速度快数倍)或云厂商 DTS/OMS 类工具(支持跨版本异构同步、可反向增量,能大幅压缩停机窗口)
阶段 4|收尾
ANALYZE TABLE核心表,打开 8.0 新能力(原子 DDL、角色、降序索引、不可见索引、clone 插件、资源组)- 更新备份策略(xtrabackup 8.0 / 逻辑备份+binlog)并做一次恢复演练
- 更新监控项(替换失效 SQL)、更新文档与应急预案
- 复盘遗留技术债(如暂时放宽的 sql_mode),排期关闭
(4). 最容易翻车的 TOP 8
| # | 现象 | 根因 | 预防 |
|---|---|---|---|
| 1 | 实例起不来 | cnf 里有query_cache_*、innodb_large_prefix等废弃参数 | 测试环境先试启动 |
| 2 | 应用连不上 | caching_sha2_password+ 老驱动 / TLS 版本不匹配 | 升级驱动或改认证插件 |
| 3 | 表“不见了” | lower_case_table_names不一致 | 初始化时保持一致 |
| 4 | 某天突然全线 Access denied | 密码 180 天过期 | PASSWORD EXPIRE NEVER |
| 5 | 列表页重复/漏数据 | 排序规则变 + 缺 ORDER BY | 补确定性 ORDER BY |
| 6 | 个别 SQL 从 10ms 变 10s | 执行计划回退 | 上线前 EXPLAIN 基线对比 |
| 7 | TIMESTAMP 默认值/NULL 行为变了 | explicit_defaults_for_timestamp8.0 强制 ON | 逐表核对建表语句 |
| 8 | GROUP BY/ 除零 / 截断报错 | 严格 sql_mode | 改 SQL,别关模式 |
(5). 三条落地建议
- 别为了省事跳过 5.7 这一档(除非走逻辑迁移), 80% 的兼容性问题在 5.7 就会暴露,越早修成本越低,而且 5.7 是唯一能跑
mysqlsh util.checkForServerUpgrade的前置跳板- 演练 ≥ 2 次,其中一次必须含完整回滚, 第一次演练的目标是发现问题,不是成功
- 用云数据库就优先走厂商升级/DTS 服务,兼容性问题会被前置拦截,比自己搬二进制省事得多
8.总结
MySQL 8.0 相比 5.6 是一次质变, 它不仅带来了窗口函数、CTE、角色等现代数据库必备功能,更通过原子 DDL、事务性数据字典和默认
utf8mb4等底层架构的革新,为数据一致性和安全性提供了更强的保障, 对于任何仍在使用 5.6 的系统,制定向 8.0 的迁移计划都是一个非常值得投入的方向