很多 Java 项目的技术栈已经更新了好几轮。
JDK 从 8 升到了 17、21,Spring Boot 从 2.x 升到了 3.x 甚至 4.x,Redis、Nginx、Docker 镜像也在不断更新。
但打开数据库服务器,可能仍然会看到一个非常熟悉的版本:
MySQL 8.0。
过去这并没有什么问题,MySQL 8.0 长期承担着大量生产系统的主力数据库角色。
但到了 2026 年,这件事情已经发生变化。
Oracle 官方明确说明:从 2026 年 4 月发布 MySQL 8.0.46 开始,MySQL 8.0 正式到达 End of Life。 官方同时建议 MySQL 8.0 用户迁移到 MySQL 8.4 LTS 或后续受支持版本。
这意味着,“数据库现在还能正常运行”已经不能作为继续停留在 8.0 的充分理由。
对于一个典型 Java 项目,更现实的问题已经变成:
MySQL 8.0 EOL 之后,到底应该升级到 8.4 LTS,还是一步到位迁移到新的 9.7 LTS?
答案并不是简单的“版本越高越好”。
对于绝大多数仍运行在 MySQL 8.0 上的存量 Java 系统,我更建议:
先把 8.4 LTS 作为第一阶段迁移目标,再根据项目生命周期决定是否继续升级 9.7 LTS。
原因不仅是稳定性,更重要的是 MySQL 官方升级路径本身就决定了 8.4 是一个非常关键的节点。
一、2026 年的 MySQL 版本体系已经变了
以前我们理解 MySQL 版本非常简单:
5.6 → 5.7 → 8.0。
几年出现一个主流大版本,大多数企业跟着升级即可。
现在 MySQL 已经正式采用两条发布路线:
| 发布路线 | 主要特点 | 更适合 |
|---|---|---|
| LTS | 长期支持、功能集合相对稳定 | 企业生产系统 |
| Innovation | 更快获得新特性和行为变化 | 新项目、技术验证、自动化测试成熟的团队 |
Oracle 官方说明,LTS 更适合需要稳定功能集合和较长支持周期的环境;Innovation Release 则更强调快速获得新功能和改进。
而到了 2026 年,还有一个容易产生误解的变化:
MySQL 9.7 本身已经是 LTS。
也就是说,现在不能再简单理解成:
“8.4 是稳定版,9.x 全都是创新版。”
更准确的关系是:
flowchart LR
A["MySQL 8.0<br/>已 EOL"] --> B["MySQL 8.4 LTS"]
B --> C["MySQL 9.0 ~ 9.6<br/>Innovation 演进"]
C --> D["MySQL 9.7 LTS"]
D --> E["后续采用<br/>YY.M 日历版本"]
MySQL 9.7 是旧数字版本体系下最后一个版本线。Oracle 已经开始转向日历版本命名,例如 MySQL 26.7 代表 2026 年 7 月版本。(MySQL 개발자区)
所以现在选择数据库版本时,应该关注的已经不是:
8.x 还是 9.x?
而是:
当前项目应该停在哪一个合适的 LTS 节点?
二、为什么 MySQL 8.0 项目仍然应该先关注 8.4
既然 9.7 已经是新的 LTS,一个很自然的问题就是:
那我现在还在 MySQL 8.0,为什么不直接上 9.7?
这里最重要的一点其实是 官方升级路径。
MySQL 官方升级文档明确给出了:
MySQL 8.0 → MySQL 8.4 LTS
这一升级路线,并支持 In-place Upgrade、Logical Dump and Load 以及 Replication 等方式。
同时官方还明确说明:
Bugfix 或 LTS 系列不能被直接跳过。
因此对于目前仍停留在 MySQL 8.0 的系统而言,8.4 并不是一个没有意义的“过渡版本”,而是升级链路中的关键 LTS 节点。
从工程角度看,更合理的路线是:
flowchart LR
A["MySQL 8.0"] --> B["升级兼容性检查"]
B --> C["MySQL 8.4 LTS"]
C --> D["稳定运行与观察"]
D --> E{"是否需要继续升级?"}
E -->|"暂时不需要"| F["继续维护 8.4 LTS"]
E -->|"需要更长生命周期"| G["评估 MySQL 9.7 LTS"]
这样有一个很大的好处:
一次升级只处理一层主要变化。
如果直接把数据库、驱动、认证方式、SQL 行为以及整个应用运行环境同时进行大跨度调整,出现问题以后会很难判断到底是哪一层导致的。
三、那什么时候应该考虑直接以 9.7 LTS 为最终目标?
这里需要强调:
MySQL 9.7 LTS 并不是“不建议用于生产”。
恰恰相反,它本身就是新的长期支持版本。
真正的问题是你的项目处于什么阶段。
如果是一个已经稳定运行多年的存量系统,并且当前数据库还是 MySQL 8.0,那么先迁到 8.4 往往更加容易控制风险。
如果正在进行一次较大的基础设施重构,例如同时准备:
- 升级 JDK;
- 升级 Spring Boot;
- 更换服务器;
- 重建数据库集群;
- 更换容器运行环境;
- 调整数据库高可用方案;
那么就可以把 9.7 LTS 纳入最终目标版本进行整体评估。
可以简单理解为:
| 项目情况 | 更适合的策略 |
|---|---|
| 老系统,只想解决 8.0 EOL | 优先 8.4 LTS |
| 项目稳定,不需要新数据库能力 | 8.4 LTS |
| 正在进行整体基础设施升级 | 评估 9.7 LTS |
| 新系统,没有历史兼容包袱 | 可以直接评估最新 LTS |
| 自动化测试不足、业务风险较高 | 优先减少升级跨度 |
| 有完整 DBA、灰度、回归体系 | 可以规划更积极的版本路线 |
数据库升级并不是版本号竞赛。
真正重要的是控制一次升级所引入的变量数量。
四、升级 MySQL 8.4,最容易踩坑的可能不是 SQL
很多开发者看到数据库升级,第一反应通常是:
我的 SQL 还能不能正常执行?
SQL 当然需要测试。
但从 MySQL 8.0 升级 8.4 时,一个非常值得优先检查的问题其实是:
数据库用户认证插件。
mysql_native_password 在 MySQL 8.0.34 就已经被标记为废弃;到了 MySQL 8.4,它默认被禁用;到了 MySQL 9.0,它已经被删除。
整个变化过程可以表示为:
flowchart LR
A["MySQL 8.0.34<br/>开始废弃"] --> B["MySQL 8.4<br/>默认禁用"]
B --> C["MySQL 9.0+<br/>正式移除"]
因此,数据库升级前非常值得执行一次:
SELECT
user,
host,
plugin
FROM mysql.user;
如果发现某个应用用户仍然使用:
mysql_native_password
就应该提前处理,而不是等数据库升级以后 Spring Boot 启动失败才开始排查。
目前更加合理的认证方式通常是:
caching_sha2_password
例如:
ALTER USER 'app_user'@'%'
IDENTIFIED WITH caching_sha2_password
BY 'YourStrongPassword';
但生产环境不要直接修改。
更稳妥的做法是先创建测试用户或在测试环境修改,然后确认 Java 应用、Connector/J 和连接池全部能够正常工作。
五、Java 项目升级数据库,Connector/J 必须一起检查
一个 Java 项目连接 MySQL,中间其实经过了多层组件:
flowchart LR
A["Spring Boot"] --> B["HikariCP / Druid"]
B --> C["JDBC"]
C --> D["MySQL Connector/J"]
D --> E["MySQL Server"]
所以数据库升级以后出现连接异常,并不意味着问题一定出在数据库本身。
很多维护时间比较长的项目,可能已经升级过 Spring Boot、JDK、MyBatis,但 Connector/J 一直没有认真检查。
Maven 项目可以执行:
mvn dependency:tree
然后搜索:
mysql-connector-j
Gradle 项目则可以使用:
./gradlew dependencies
重点不是看 pom.xml 里有没有声明 MySQL Driver,而是看:
最终运行时真正加载的是哪个 Connector/J。
截至目前,MySQL 官方当前 Connector/J 版本支持 MySQL Server 8.0 及以上版本,并支持 JRE 8 及以上运行环境。
这并不意味着所有历史 Connector/J 都应该继续使用。
数据库升级正好也是一个检查 JDBC Driver 技术债的机会。
六、不要为了老项目长期重新打开 mysql_native_password
MySQL 8.4 默认关闭 mysql_native_password 后,一些历史项目可能无法正常连接。
这时候一种非常直接的处理方式是重新启用旧认证插件。
短时间作为应急迁移方案,它可能解决问题。
但如果把它作为长期方案,本质上只是把问题继续推迟。
因为官方已经明确给出了它的生命周期:
- MySQL 8.0.34:废弃;
- MySQL 8.4:默认关闭;
- MySQL 9.0:删除。
所以真正合理的路线应该是:
flowchart LR
A["发现旧认证账号"] --> B["检查 Connector/J"]
B --> C["升级客户端依赖"]
C --> D["切换新认证方式"]
D --> E["Java 应用完整验证"]
E --> F["淘汰旧认证"]
这样以后继续迁往新的 LTS 时,就不需要重新处理同一笔技术债。
七、另一个容易被忽略的问题:JDK 与 TLS
认证并不是唯一需要检查的连接问题。
对于比较新的 Java 项目来说,TLS 通常不会成为主要障碍。
真正需要注意的是一些历史系统,例如:
- 较早版本的 JDK 8;
- 很老的 Connector/J;
- 多年没有升级的 Linux 环境;
- 历史遗留下来的 SSL/TLS 参数。
这种项目平时可能一直正常运行,但数据库或者驱动升级以后,TLS 协商方式也可能暴露问题。
MySQL 官方当前 Connector/J 文档特别提到,较早的 Oracle Java 8 版本在 TLS 能力方面存在版本差异,例如 Java 8u261 之前的平台需要额外考虑 TLS 1.3 支持问题。
所以升级测试不要只验证:
SELECT 1;
能够执行。
真正需要验证的是完整 Java 应用。
八、升级前先让 MySQL 自己检查一次
MySQL Shell 提供了一个非常实用的工具:
util.checkForServerUpgrade()
它的作用就是在真正升级之前检查当前 MySQL 实例和目标版本之间可能存在的兼容问题。官方也明确建议在数据库升级前运行 Upgrade Checker。
例如:
util.checkForServerUpgrade(
"root@127.0.0.1:3306",
{
targetVersion: "8.4.0"
}
);
也可以通过命令行执行:
mysqlsh -- util checkForServerUpgrade root@127.0.0.1:3306 \
--target-version=8.4.0
实际生产升级时,应把 targetVersion 修改为计划安装的具体目标版本。
Upgrade Checker 会执行自动检查,同时告诉你还有哪些内容需要人工进一步确认。
相比直接停止生产数据库然后安装新版本,这种方式显然更加可控。
九、数据库升级的测试单位应该是“应用”,而不是 MySQL
很多数据库升级测试实际上非常简单:
安装 MySQL 8.4,创建一个新数据库,启动 Spring Boot,首页能够打开。
然后得出结论:
升级没有问题。
这种测试是不够的。
因为真实生产数据库可能已经积累了很多特殊情况:
- 历史表结构;
- 大数据量表;
- 老索引;
- 特殊字符集和排序规则;
- 存储过程;
- Trigger;
- Event;
- 复杂动态 SQL;
- 历史脏数据;
- 特殊数据库账号。
这些东西在一个刚创建的空数据库里根本不存在。
更加可靠的测试路线应该是:
flowchart LR
A["生产 MySQL 8.0"] --> B["备份 / 克隆"]
B --> C["隔离测试环境"]
C --> D["升级 MySQL 8.4"]
D --> E["部署真实 Java 应用"]
E --> F["完整业务回归"]
F --> G["性能对比"]
MySQL 官方升级文档同样建议先在测试系统完成升级验证,确认工作正常以后再处理生产系统。
十、Java 应用至少要回归这些内容
数据库升级验证不要只测几个 Controller。
至少应该覆盖以下几类场景:
| 测试项 | 重点检查 |
|---|---|
| 数据库连接 | 启动、重连、连接池初始化 |
| 普通 CRUD | 新增、查询、修改、删除 |
| 复杂查询 | JOIN、GROUP BY、排序、分页 |
| 事务 | 提交、回滚、异常事务 |
| MyBatis | 动态 SQL、批处理 |
| JSON | JSON 字段读写和函数 |
| 大字段 | TEXT、BLOB |
| 定时任务 | Spring Scheduling、XXL-JOB、Quartz |
| 慢 SQL | 执行计划是否变化 |
| 高并发 | 连接数、锁等待 |
| 批量任务 | 大批量插入和更新 |
| 报表 | 长 SQL、聚合查询 |
对于关键 SQL,可以重新执行:
EXPLAIN
SELECT ...;
如果希望看到真实执行信息,还可以根据场景使用:
EXPLAIN ANALYZE
SELECT ...;
重点关注升级前后是否出现明显的执行计划和性能变化。
十一、生产升级之前,必须先设计回滚
Java 应用发布失败以后,我们通常可以重新部署上一版 JAR。
数据库升级则没有这么简单。
数据库真正危险的地方在于:
升级完成后,业务可能已经继续产生新数据。
假设晚上 23:00 完成数据库升级,23:30 发现一个核心业务出现兼容问题。
这时候再问:
怎么退回 MySQL 8.0?
通常已经太晚了。
所以数据库升级必须同时存在两份方案:
Upgrade Plan 和 Rollback Plan。
至少需要提前回答:
- 原数据库是否继续保留?
- 升级过程中业务是否停止写入?
- 新版本产生的数据如何处理?
- 应用 JDBC 地址如何切回?
- 旧数据库环境保留多久?
- 数据备份是否真正做过恢复测试?
- 出现什么级别的问题必须回滚?
MySQL 官方同样反复强调升级前备份数据,并建议首先在测试系统执行升级。
对于重要业务来说:
“我已经有备份”还不够。
真正有价值的是:
我已经验证这个备份能够恢复。
十二、核心业务更适合新环境迁移,而不是直接原地升级
对于个人博客、小型管理后台,停机维护以后直接升级数据库可能完全可以接受。
但如果是 ERP、订单、生产管理、SaaS 等核心系统,就可以考虑更加稳妥的迁移方式。
例如:
flowchart LR
A["MySQL 8.0 生产库"] --> B["同步 / 复制数据"]
B --> C["MySQL 8.4 新环境"]
C --> D["Java 应用验证"]
D --> E["控制生产写入"]
E --> F["完成最终数据同步"]
F --> G["切换 JDBC 连接"]
G --> H["观察新环境"]
这种方案最大的优势不是升级更快。
而是:
原来的数据库还在。
如果新环境出现严重问题,回滚空间远大于直接修改唯一生产实例。
MySQL 官方支持通过 In-place、Logical Dump and Load、Replication 等方式完成 8.0 到下一 LTS 的升级,可以根据系统规模选择合适方案。
十三、我更推荐的 MySQL 8.0 升级流程
对于一个典型的 Spring Boot + MyBatis + MySQL 项目,可以按照下面的顺序推进:
flowchart LR
A["确认当前 MySQL 8.0 版本"] --> B["检查数据库账号认证"]
B --> C["检查 Connector/J"]
C --> D["运行 Upgrade Checker"]
D --> E["完整备份并验证恢复"]
E --> F["克隆生产数据"]
F --> G["测试环境升级 8.4"]
G --> H["Java 应用完整回归"]
H --> I["SQL 与性能对比"]
I --> J["制定回滚方案"]
J --> K["生产灰度 / 正式迁移"]
K --> L["持续监控"]
真正升级 MySQL Server 软件本身,其实只是整个过程的一小部分。
真正决定升级是否可靠的是:
兼容性检查、应用回归、数据保护和回滚设计。
十四、到了 8.4 后,要不要继续升级 9.7?
这就回到了文章开始的问题。
如果已经稳定运行在 MySQL 8.4 LTS,而且:
- 当前功能完全够用;
- 没有生命周期压力;
- 没有明确的新版本需求;
- 系统属于高稳定性业务;
那么没有必要为了“版本更高”立即升级。
MySQL 官方对 LTS 的定位本身就是稳定功能集合和更长支持周期。
但如果你的系统还会长期维护很多年,正在规划下一轮基础设施升级,那么 9.7 LTS 就值得进入技术路线图。
这里真正应该采用的策略是:
flowchart LR
A["MySQL 8.0 EOL"] --> B["先迁移 MySQL 8.4 LTS"]
B --> C["稳定运行"]
C --> D{"是否存在升级需求"}
D -->|"没有"| E["继续维护 8.4"]
D -->|"有"| F["评估 9.7 LTS"]
所以我的建议并不是:
MySQL 9.7 不好,不要升级。
而是:
不要因为 MySQL 8.0 EOL,就把一次必要升级变成一次不必要的大跨度改造。
十五、MySQL 8.0 EOL 真正提醒我们的是什么
很多 Java 团队非常重视应用代码升级。
JDK 会升级。
Spring Boot 会升级。
Redis 会升级。
前端框架会升级。
Docker 镜像也会升级。
但数据库经常成为那个“只要还能运行就不要碰”的组件。
结果几年以后,整个系统可能已经进入一种奇怪状态:
应用层非常新,基础设施部分组件却已经严重落后。
这种做法最大的问题不是今天不能运行。
而是技术债会不断积累。
最开始只是:
现在没必要升级。
几年以后就可能变成:
已经不敢升级了。
MySQL 8.0 在 2026 年正式 EOL,就是一个很明确的提醒:数据库、JDBC Driver、JDK、操作系统等基础组件同样存在生命周期,不能永久依靠“还能跑”判断是否需要维护。
十六、写在最后
对于目前仍然运行 MySQL 8.0 的 Java 项目,2026 年已经到了需要认真规划升级的时候。
但升级并不意味着盲目追最新。
更加合理的思路是:
flowchart LR
A["MySQL 8.0"] --> B["处理历史技术债"]
B --> C["检查认证与 JDBC"]
C --> D["完成兼容性验证"]
D --> E["建立备份与回滚能力"]
E --> F["升级 MySQL 8.4 LTS"]
F --> G["稳定运行"]
G --> H["按实际需求评估 9.7 LTS"]
MySQL 8.4 和 MySQL 9.7 都是 LTS。
真正的区别不是哪个版本“更高级”,而是:
哪个版本更符合当前系统的迁移成本、生命周期和风险承受能力。
对于仍在 MySQL 8.0 的存量 Java 系统来说,我更倾向先把问题拆小:
先完成 8.0 → 8.4 的可靠迁移,处理认证插件、Connector/J、SQL、事务、备份和回滚等历史问题。
等系统重新站到一个受支持、稳定的 LTS 基线上,再决定下一步是否进入 9.7。
数据库升级最重要的从来不是:
“我用了最新版。”
而是:
在不破坏业务稳定性的前提下,让系统始终处于官方支持、安全、可维护,并且仍然能够继续演进的状态。

评论区 1