资讯动态

MySQL 5.7升级8.0:从准备到踩坑排查的完整指南

发布时间:2026/10/2 9:09:16 来源:尧图企业网站定制
1. 升级之前先搞清楚你的MySQL到底该不该升、能升到哪干MySQL这块的同行应该都有感触系统跑得好好的最怕听见升级两个字。生产环境动数据库搞不好就是通宵加背锅。但有些情况你躲不过——官方停止维护、安全漏洞补丁不再更新、新业务需要的新特性老版本不支持、或者你正被某个老版本的bug折磨得想骂人。这篇文章我把MySQL升级从准备到落地、再到踩坑排查的完整链路梳理一遍适合正在规划升级、或者已经被迫走在升级路上的同学参考。先说一个很多人忽略的前提升级不是版本号越大越好而是目标版本必须在官方维护周期内并且你的业务、硬件、中间件都能接得住。MySQL 5.7已经于2023年10月停止官方维护EOL还跑在5.7上的同学现在属于裸奔状态——官方不再发布任何补丁遇到高危漏洞只能自己扛。MySQL 8.0是目前最稳妥的长期支持版本8.4 LTSInnovation之后的长期支持版也在持续更新中具体选哪个看你的业务节奏。动手之前先做三件事第一摸清当前版本和运行状态。登录数据库执行SELECT VERSION(); SHOW VARIABLES LIKE innodb_version; SHOW VARIABLES LIKE character_set_server; SHOW VARIABLES LIKE collation_server;同时看一眼SHOW ENGINE INNODB STATUS\G确认没有未提交的长事务、没有堆积的复制延迟。升级前数据库本身带病运行升级就是往火堆里浇油。第二确认目标版本和操作系统兼容性。去官网查一下目标MySQL版本对操作系统的支持列表比如CentOS 7和MySQL 8.0.30以上的版本、glibc版本匹配问题这些坑都是真实存在的。最简单的办法是直接下载对应的mysql-8.x.x-linux-glibc2.12-x86_64.tar.gz包基本覆盖主流Linux发行版。但你如果是ARM架构比如华为云鲲鹏、AWS Graviton记得下载aarch64版本这个坑我见过不止一个人踩——x86包在ARM机器上直接Illegal instruction崩溃。第三梳理清楚你的数据库里有什么。有多少库、多少表、哪些用了存储过程/触发器/自定义函数、哪些是MyISAM表还在用的、JDBC驱动版本是多少、ORM框架是什么版本。这一步决定了你升级方案的选择也决定了升级完成后哪些兼容性问题会爆发。提示MySQL 8.0对MyISAM的容忍度越来越低如果还有业务表在用MyISAM建议在升级前就做好转换计划否则升级后哪怕能跑起来性能和崩溃恢复能力也会拖后腿。2. 两条路线怎么选原地二进制替换还是逻辑迁移重建MySQL升级主流的方案就两条in-place升级原地替换二进制文件和逻辑迁移逻辑备份/重建/导入。我分别讲清楚你们根据自己的场景选。2.1 in-place升级同版本大版本内小版本升级的首选in-place的意思直白停库、换掉MySQL的二进制文件、启动实例、跑系统库升级工具。它最省事适合5.7.30升5.7.42这种同大版本内的小版本升级风险相对可控。跨大版本5.7升8.0官方其实也支持in-place但劝你别这么干——8.0相比5.7改动太多原地升级一旦中间出岔子数据库起不来你就得在原目录上折腾回滚路径很窄。in-place核心流程以5.7小版本升级为例关闭数据库mysqladmin -uroot -p shutdown建议用优雅关闭不要kill进程。备份数据目录直接cp -a或rsync整个datadir到另一块磁盘。数据目录是命根子没有完整备份不配谈升级。备份配置文件/etc/my.cnf或/etc/mysql/mysql.conf.d/整体备份一份。替换二进制解压新版本tar包停库后替换。重点保留旧的datadir不要动让新二进制去读旧datadir。启动新实例观察错误日志确认没有致命报错。升级系统库执行mysql_upgrade -u root -pMySQL 8.0.16之前或直接由mysqld启动时自动执行8.0.16。这一步是必须的它负责更新mysql系统库表结构、检查所有库表的兼容性。2.2 逻辑迁移跨大版本升级的保命通道5.7升8.0、或者架构要调整比如要改字符集、要改表引擎逻辑迁移更稳。核心流程也不复杂用mysqldump导出数据mysqldump -u root -p --single-transaction --routines --triggers --events --log-errordump.log -A backup.sql。--single-transaction靠InnoDB MVCC保证备份一致性不加锁--routines和--triggers把存储过程、触发器一起备份出来--events备份事件调度器。大库建议用mydumper或xtrabackup 逻辑导入的方式单表几十G的库用mysqldump导出再导入时间你是等不起的。在新环境装好目标版本MySQL把backup.sql导入。业务切换前做一次数据校验比对总行数、关键表的最大自增ID、核心业务表的COUNT(*)防止导入过程中丢数据。两者怎么选参照下表面情况维度in-place升级逻辑迁移升级跨度同大版本内小版本跨大版本或大版本内均可耗时分钟级取决于表数量小时级取决于数据量回滚难度中等备份了datadir可回滚低旧库完全没动架构调整不支持完全支持适用场景小版本补丁、版本接近、停机窗口短大版本跳跃、架构调整、你有充足时间注意如果你决定走in-place回滚依然要靠升级前的物理备份。升级前数据目录备份是底线谁也不能保证升级100%顺利。3. 升级实操全流程二进制包下载、目录替换、系统库升级与启动验证下面按最常见的场景展开——CentOS 7/RHEL 7上MySQL 5.7升到8.0逻辑迁移方式。这套流程我实际跑过多次每一步都验证过照着做基本不会翻车。3.1 准备阶段下载、校验、确认glibc兼容首先去MySQL官网下载页找到MySQL Community Server 8.x.x选Linux - Generic下的mysql-8.x.x-linux-glibc2.17-x86_64.tar.gz注意CentOS 7的glibc版本是2.17所以下载glibc2.17的版本兼容性最好下载glibc2.12名字的版本也兼容但别下glibc2.28的那是给CentOS 8/9用的。下载完先对MD5md5sum mysql-8.0.xx-linux-glibc2.17-x86_64.tar.gz去官网核对MD5值一致再继续。这一步很多人跳过建议别懒——官方下载页挂了MD5不是给你看的是让你验的。3.2 新旧环境目录规划我习惯性的规划一个统一目录结构避免在裸系统上把MySQL文件散落得到处都是/opt/mysql/ # 基础目录 ├── mysql-5.7.44 # 旧版本保留不动 ├── mysql-8.0.36 # 新版本 ├── data/ # 数据目录 ├── logs/ # 错误日志、慢查询日志 ├── backup/ # 备份文件 └── tmp/ # 临时文件mysqldump导出文件放这这样新老版本共存互不干扰迁移完确认无误再删除旧目录心里踏实。3.3 老库逻辑导出mysqldump -u root -p --single-transaction --routines --triggers --events --set-gtid-purgedOFF -A /opt/mysql/backup/full_backup.sql 2 dump_error.log几个参数解读一下--single-transaction保证InnoDB表的一致性快照不锁表线上业务可以继续写只是导出期间数据被锁定在快照时间点。--routines --triggers --events带出存储过程、触发器和事件调度器缺了升级后应用跑着跑着报PROCEDURE does not exist就晚了。--set-gtid-purgedOFF5.7默认没开GTID的库不加这个也没事但如果开了GTID一定要加OFF否则导入8.0时会报GTID冲突。-A全库导出包括mysql系统库。系统库的权限、用户信息全靠这个带过去。导出完之后grep -E ^CREATE DATABASE|^USE full_backup.sql看一眼确认该导的库都导出来了也可以wc -l full_backup.sql看下体量是否合理。3.4 新环境安装初始化解压新版本tar -xzf mysql-8.0.36-linux-glibc2.17-x86_64.tar.gz -C /opt/mysql/ ln -s /opt/mysql/mysql-8.0.36-linux-glibc2.17-x86_64 /opt/mysql/mysql8创建mysql用户如果还没有groupadd mysql useradd -r -g mysql -s /bin/false mysql mkdir -p /opt/mysql/data /opt/mysql/logs /opt/mysql/tmp chown -R mysql:mysql /opt/mysql初始化数据目录这个步骤很重要8.0已经不再用mysql_install_db脚本改成了mysqld --initialize/opt/mysql/mysql8/bin/mysqld --initialize --usermysql --basedir/opt/mysql/mysql8 --datadir/opt/mysql/data注意看初始化命令的日志输出会生成一个临时root密码形如[Note] A temporary password is generated for rootlocalhost: xxxxxxxx这个临时密码一定要保存好第一步登录要用。如果初始化时报libaio.so.1缺失装一下依赖yum install -y libaio libaio-devel numactl。接着配置my.cnf8.0默认参数和5.7差异很大几个核心配置我给个起步模板[mysqld] usermysql basedir/opt/mysql/mysql8 datadir/opt/mysql/data socket/tmp/mysql.sock port3306 pid-file/opt/mysql/logs/mysqld.pid log-error/opt/mysql/logs/mysqld.err # 8.0推荐字符集 character-set-serverutf8mb4 collation-serverutf8mb4_0900_ai_ci # InnoDB缓冲池建议设为物理内存的60%-70% innodb_buffer_pool_size8G innodb_log_file_size1G # 兼容旧版SQL行为按需开启 # sql_modeSTRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION # 如果业务涉及分区表建议显式开启 # innodb_file_per_tableON # 8.0默认认证插件是caching_sha2_password旧客户端连不上时可以改 # default-authentication-pluginmysql_native_password注意collation_server我写的是utf8mb4_0900_ai_ci这是8.0默认排序规则。如果老库用的是utf8mb4_general_ci导入后所有字段的排序规则需要兼容处理后面章节细说。3.5 启动新实例并导入数据启动/opt/mysql/mysql8/bin/mysqld --defaults-file/etc/my.cnf 确认起来后用临时密码登录mysql -u root -p修改root密码ALTER USER rootlocalhost IDENTIFIED BY YourStrongPass;然后导入全量备份mysql -u root -p -h 127.0.0.1 /opt/mysql/backup/full_backup.sql导入过程中如果报错先不要慌看具体错误信息。最常见的错误有Unknown collation utf8mb4_general_ci之类的报错说明目标库的排序规则和原库不一致导入前先在新库实例执行SET NAMES utf8mb4 COLLATE utf8mb4_general_ci或者直接修改配置文件统一排序规则。ERROR 1418 (HY000)之类关于函数创建失败的报错多半是log_bin_trust_function_creators参数没开执行SET GLOBAL log_bin_trust_function_creators 1;再导入完成后再关掉。ERROR 1062主键冲突大概率是老库存在重复数据单独排查处理别一股脑重导。3.6 升级后的自检报表导入完成不代表事情结束按照我自己的一套自检清单逐项过一遍-- 1. 确认版本 SELECT VERSION(); -- 2. 确认所有库表引擎 SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN (mysql,information_schema,performance_schema,sys); -- 3. 检查是否有MyISAM残留 SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE ENGINE MyISAM AND TABLE_SCHEMA NOT IN (mysql,information_schema,performance_schema,sys); -- 4. 检查字符集是不是全部转过来了 SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_COLLATION LIKE %general_ci% OR TABLE_COLLATION LIKE %latin1%; -- 5. 检查所有存储过程是否能正常SHOW出来 SHOW PROCEDURE STATUS; -- 6. 确认所有用户都存在 SELECT user, host, plugin FROM mysql.user; -- 7. 关键业务表抽样验证数据 SELECT COUNT(*) FROM your_key_table;自检报表这些SQL建议升级完跑完把结果存一份档案出问题也好追溯。4. 大版本跨级后的兼容性盲区认证插件、sql_mode、字符集、SQL语法5.7升8.0最坑人的不是数据本身而是行为差异。数据还是那些数据但数据库的脾气变了——应用的SQL可能跑不起来、连不上、结果集排序不一样。我列几个高频雷区每个都是实战中踩过、帮读者排过的。4.1 认证插件客户端一夜之间全军覆没MySQL 8.0默认的认证插件从mysql_native_password改成了caching_sha2_password。这个改动对8.0的新客户端MySQL 8.0自带的mysql客户端、Connector/J 8.0以上版本、Navicat 16以上版本没有影响但如果你还在用PHP 7.2以下的mysqli扩展Python的mysqlclient老版本1.4.x以下或PyMySQL0.9.x以下的老版本Navicat 15及之前的老版本基于MariaDB的客户端驱动那你大概率会遇到Authentication plugin caching_sha2_password cannot be loaded这类报错。解决办法两条全局改回旧插件不推荐长期用新特性会受限ALTER USER user% IDENTIFIED WITH mysql_native_password BY password;或者在my.cnf设[mysqld] default-authentication-pluginmysql_native_password但注意这个参数在8.0.24之后就没效果了还是得用ALTER USER逐个改。升级你的客户端、驱动、ORM框架彻底拥抱caching_sha2_password。这才是根治方案安全性和性能都更好。尤其是公司里统一维护的JDBC驱动版本8.0升级前就要拉齐。4.2 sql_mode同样的SQL不同的脾气MySQL 5.7默认的sql_mode是ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION。8.0把这套基本继承下来但8.0.17之后把NO_AUTO_CREATE_USER彻底移除了GRANT语句不能创建用户了必须先CREATE USER再GRANT同时新增了NO_ZERO_DATE之类的行为强化。最常见的问题是两个第一个是 ONLY_FULL_GROUP_BY 导致的分组查询报错。老库允许这种写法SELECT id, name, SUM(amount) FROM orders GROUP BY name;8.0下直接报SELECT list is not in GROUP BY clause and contains nonaggregated column。说明你的SQL本身不严谨——id没被GROUP BY也没被聚合。这是5.7就存在的严格模式但很多人是在8.0升级后才第一次见到这个报错因为老库的sql_mode被手动改宽过。解决办法改SQL把id也加到GROUP BY里或者用子查询。千万别为了过升级就把sql_mode一删了之严格模式是保护数据质量的重要防线。第二个是日期类型 0000-00-00 的拒绝。老业务很多表里残留了默认值0000-00-00的日期字段这在8.0严格模式下直接插入报错。处理方式先查出来SELECT table_name, column_name FROM information_schema.columns WHERE table_schema your_db AND data_type IN (date,datetime,timestamp) AND column_default 0000-00-00;然后逐表更新为合法值比如1970-01-01或改默认值。4.3 字符集与排序规则utf8mb4的迁移灾难5.7时代大家普遍用utf8mb4_general_ci8.0的默认排序规则是utf8mb4_0900_ai_ci。虽然都是utf8mb4编码但排序规则不同会带来几种后果表字段排序规则如果还是utf8mb4_general_ci而查询条件里用了COLLATE utf8mb4_0900_ai_ci会报COLLATION utf8mb4_general_ci is not valid for CHARACTER SET utf8mb4之类的不兼容报错实际报错可能是Illegal mix of collations。排序结果不同。utf8mb4_general_ci不区分大小写、不区分重音但utf8mb4_0900_ai_ci引入了Unicode 9.0的排序规则——某些特殊字符比如中文的排序位置、带重音字符排序结果会有差异。牵一发动全身数据库默认排序规则改了所有新建表的默认值就变了老表和新建表JOIN的时候排序规则不一致直接报错。我的建议升级后的新库全部统一到utf8mb4_0900_ai_ci并在导入前就定好默认值。老表保留原排序规则的话在JOIN时显式指定COLLATE但我不推荐这种混乱状态长痛不如短痛一次性把老表也转过来ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;执行前务必评估大表几千万行的执行时间该操作会锁表重建。4.4 被移除的SQL语法和功能8.0大刀阔斧砍掉了一批5.7能用的东西你升级后如果还依赖以下功能需要提前改造NO_AUTO_CREATE_USER模式移除GRANT不再隐式创建用户encode/decode函数弃用PROCEDURE ANALYSE()移除一部分查询缓存Query Cache相关参数移除8.0彻底删了这个功能mysql_upgrade在8.0.19后转为自动执行但工具本身还在这些大部分只影响存量脚本所以升级前把应用里的SQL全面扫一遍重点搜GRANT、PROCEDURE ANALYSE、ENCODE(、DECODE(几个关键字。5. 升级后最容易翻车的高频现场现象、排查链路与修复方法这部分我把升级后用户最常反馈的几个问题做个复盘每个都给排查思路和解决路径。5.1 现象一Navicat/老客户端报SSL connection error或认证插件无法加载升级完8.0后Navicat 15及更早版本连接时报错信息五花八门有的报SSL有的报认证插件无法加载。很多人第一反应去查SSL配置其实这俩的根源往往是同一个——客户端版本太老不支持caching_sha2_password。排查链路SELECT user, host, plugin FROM mysql.user WHERE userroot;看root的认证插件是不是caching_sha2_password。如果确认是再看客户端版本。Navicat 12/15、MySQL Workbench 6.x/8.0早期版本都不支持。临时方案把该用户的认证方式改回ALTER USER root% IDENTIFIED WITH mysql_native_password BY password;重启一遍Navicat就能连上。但记住mysql_native_password在8.4已经被标记为废弃迟早要改回来。所以我的建议是顺手把客户端升级到最新版一次性解决问题。5.2 现象二升级后发现数据库连接频繁超时、性能比5.7还差这个情况不少见。排除了网络、硬件问题后重点看几个8.0的新坑1自适应哈希索引AHI重建带来的预热期。8.0的InnoDB缓冲池和自适应哈希索引在升级后需要重新预热刚启动的前30分钟到1小时读性能会比5.7稳定期差。这个不用慌跑一段时间自己会恢复。忍不了就加强innodb_buffer_pool_dump_at_shutdownON和innodb_buffer_pool_load_at_startupON下次重启会自动加载热数据。28.0默认的redo log配置变了。5.7默认innodb_log_file_size48M之类的较小值8.0默认调大了但如果你从5.7原地升级到8.0旧配置的redo log大小会被沿用——太小的话写入性能上不去。看下SHOW VARIABLES LIKE innodb_log_file_size;如果只有几百M建议改到1G以上并重启。3performance_schema的开销变化。8.0的performance_schema默认开启且采集项更多性能开销大约3%-5%。业务低峰期开没问题高峰期如果机器本就不宽裕可以适当关闭部分采集项。5.3 现象三应用联调时报存储过程行为不一致、函数不存在场景还原5.7里创建的存储过程升级8.0后调用一会儿正常一会儿报错再一看SHOW CREATE PROCEDURE xxx发现定义里某些语法变了。这通常是两个原因叠加一是8.0对存储过程的解析更严格了比如隐式类型转换规则、GROUP BY处理变化二是导入时--routines没加全导致存储过程没导过来。后者纯粹是操作遗漏前者需要逐个存储过程Review并调整。建议升级前就输出所有存储过程的定义存档SELECT ROUTINE_NAME, ROUTINE_DEFINITION FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA your_db;归档后逐个比对8.0兼容性。MySQL升级这件事技术上不复杂复杂的是没想到。我见过有人升级前忘了查sql_mode差异结果上线一周后被报表部门追着骂也见过有人因为没提前拉齐JDBC驱动版本升级完所有微服务连不上数据库只能连夜回滚。把准备工作做在前头把兼容性清单过一遍升级其实就是一个备份、换包、导入、验证的流程而已。最后多提一句升级窗口最好选在业务最低峰留足回滚时间并且一定让团队里能拍板的人在旁边待命——数据库升级永远是安全第一、速度第二。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑