☰
乌班图 MySQL 小版本升级全攻略:备份、回滚与主从实践
2026/10/10 12:54:29 网站建设 项目流程

1. 先弄清楚:你所说的小版本升级,到底是哪种升级

前阵子收到安全公告,说我那台乌班图(Ubuntu)22.04 上的 MySQL 8.0.34 需要升级到 8.0.36 以上,当时我的第一反应是:这不就是 apt 换一下版本号的事吗?可真要动手才发现,乌班图 MySQL 小版本升级这件事,说简单也简单,说坑也是真不少。一台跑了三年多的 8.0.35,数据目录、慢查询配置、监控脚本都稳定地耦合在一起,我不能只改一个版本号就完事。这篇文章就围绕“乌班图 MySQL 小版本升级”这个具体场景,把版本确认、备份回滚、三条主流升级路径、执行时的坑、主从环境顺序、以及升级后的验证全部讲清楚。适合自己买了服务器、或者在公司内网跑 MySQL 的朋友,尤其是那种担心升级丢数据、服务起不来的读者。

1.1 先分清:小版本升级和大版本升级是两码事

MySQL 的版本号是三段式X.Y.Z,X 是主版本号,Y 是发布系列号,Z 是补丁版本号。举个例子:8.0.36 就是 8.0 系列的第 36 个补丁版。我们通常说的“小版本升级”,指的是同一个 Y 之下 Z 的变化,比如 8.0.35 升到 8.0.36,或者 5.7.35 升到 5.7.44。而“5.7 升到 8.0”这种属于大版本升级,执行逻辑和风险完全不在一个档次。

我见过不少朋友把两件事混在一起,拿 5.7 升 8.0 的教程来给 8.0.35 升 8.0.36 用,结果中途卡在数据字典检查流程上,折腾半天才发现方向不对。小版本升级的核心是:数据字典结构基本不变,主要替换的是二进制程序,所以理论上比大版本升级安全得多。但也正因为“看起来简单”,很多人会跳过备份、忽略环境验证,真出了问题才发现自己连回滚的底气都没有。

1.2 乌班图上 MySQL 的三种安装来源,对应不同升级方式

升级方式高度依赖当初你是“怎么装上来”的。我梳理过最常见的三种安装来源,升级方式差别很大:

安装来源典型部署方式升级本质最大风险点
apt 仓库安装(系统自带或官方仓库)apt install mysql-server通过 apt/dpkg 替换二进制包源优先级、版本被 hold、依赖冲突
离线 deb 包安装dpkg -i xxx.deb手动替换二进制包依赖缺失、安装顺序错误
官方 tar.gz 二进制包部署解压到/usr/local/mysql手动替换程序目录权限不一致、数据目录被误覆盖

我实际工作中遇到最多的是第一种:服务器用 apt 装好 MySQL,然后日常维护都在 apt 体系内跑。内网环境则大量用第二种离线 deb。第三种一般出现自运维风格比较“硬核”的朋友手里。下面三条路径都会给到,但重点会放在第一、第二种上。

1.3 升级前先花三分钟看清现状

不管你最终选哪条路径,动手之前先确认现状。正常情况下,用下面这几条命令就能拿到关键信息:

mysql --version mysql -u root -p -e "SELECT VERSION(); SHOW VARIABLES LIKE 'datadir';" dpkg -l | grep mysql-server

如果现在服务已经挂了,连不上 MySQL,也可以通过dpkg -l | grep mysql来确认已安装包的版本,或者直接看/var/log/mysql/error.log顶部的版本标识。另外,乌班图的/etc/mysql/目录下会有多个配置片段,升级后一些配置项可能被新版本废弃或改名,所以我通常会先把整个/etc/mysql/目录备份一份。这个操作成本极低,但收益很大——万一升级后启动参数不兼容,你至少能快速对比出差异。

2. 备份和回滚预案:小版本升级前必做的三件事

2.1 别以为小版本升级就不需要备份

有些朋友会说,小版本升级又不改数据文件,为什么非要备份?实际上,升级过程中磁盘写满、中途断电、新二进制和现有数据文件格式有细微不兼容,这些情况在乌班图上我都见过。InnoDB 的数据字典一般不会动,但意外一旦发生,没有备份就只能靠 binlog 追溯,而 binlog 没有开启的话就是灾难。

我处理过一个真实案例:某台内网服务器做 8.0.35 到 8.0.36 升级时,因为/var/lib/mysql所在分区剩余空间不足,MySQL 启动直接失败,日志里全是磁盘写入错误。幸好那哥们之前做了一个物理冷备,最后用备份恢复,半小时内就恢复了业务。所以我的建议是:至少保留一份物理备份,有条件再做一份逻辑备份。

逻辑备份最常用的是mysqldump:

mysqldump -u root -p \ --single-transaction --quick \ --routines --events --triggers \ --all-databases > alldb_$(date +%F).sql

--single-transaction对 InnoDB 表比较友好,备份过程中不会长时间锁表;但 MyISAM 表仍然可能被短暂锁定。逻辑备份的好处是 SQL 文本可读、可筛选,坏处是恢复慢,数据量大时可能要跑很久。

物理冷备也很直观:

systemctl stop mysql tar -czf /backup/mysql_datadir_$(date +%F).tar.gz /var/lib/mysql systemctl start mysql

这种备份恢复最快,升级翻车直接把 tar 包解回去就好。如果你用的是 MySQL 8.0.17 以上版本,还可以考虑 Clone Plugin 做在线克隆,不影响源实例,但配置起来比前两种稍复杂一点。

2.2 回滚判断标准:能不能原地降级?

小版本升级之后能不能降级?绝大多数 8.0.x 之间的补丁版可以原地降级,前提是数据字典没有被新版修改。但 8.0 早期版本和后期版本之间并不绝对,5.7 升到 8.0 之后基本上不能直接降回 5.7。所以我有一个习惯:升之前把旧版本的 deb 包或官方 tar.gz 包也下载保存一份,万一新版本启动失败,直接换回旧程序,配合物理备份恢复,这样心里才踏实。

2.3 记录环境快照,避免升级后两眼一抹黑

升级前花两分钟把环境信息记下来,不用写文档,自己存个备忘录就行。重点包括:

  • datadir 路径,通常默认是/var/lib/mysql
  • 配置文件路径,乌班图上主要是/etc/mysql/my.cnf和/etc/mysql/mysql.conf.d/mysqld.cnf
  • 端口和 socket 路径,默认是3306和/var/run/mysqld/mysqld.sock
  • 启动用户和目录权限,一般是mysql:mysql

升级后如果连不上,第一件事就是拿这些信息做对比,而不是盲目改配置。我遇到过不少报 2003 连接错误的情况,最后发现就是 socket 路径变了,或者 bind-address 配置被新版本调整过。

3. 三条典型升级路径:从源锁定到离线包,按场景选

3.1 路径 A:官方 APT 仓库精确锁定小版本

如果你的乌班图能访问公网,推荐用 MySQL 官方 APT 仓库升级,这是最省事的路径。先添加官方仓库:

wget https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb sudo dpkg -i mysql-apt-config_0.8.29-1_all.deb sudo apt update

这个配置包的版本号以后可能会更新,具体以官网下载页为准。安装过程中会弹窗问你要选哪个 MySQL 版本,选择 8.0 保存即可。

然后查看当前可用的 MySQL 版本:

apt-cache policy mysql-server apt list -a mysql-server

你会看到一系列候选版本,包括8.0.36-1ubuntu22.04之类的版本号。精确安装目标版本:

sudo apt-get install mysql-server=8.0.36-1ubuntu22.04

注意版本号格式是“上游版本号-1ubuntu系列”,具体以apt-cache policy输出为准。如果你之前装的是乌班图系统源里的 mysql-server,切换到官方仓库后 apt 会自动按官方仓库的版本解析。

升级完成后重启服务:

sudo systemctl restart mysql

这里说明一下为什么建议用等号精确指定版本,而不是直接apt-get upgrade。在生产环境里,直接 upgrade 可能会把 MySQL 大版本也一并带上去,或者装了还没验证过的补丁版。指定版本号能保证你只做“小版本升级”,不会顺手把其他系统组件也动一遍。

3.2 路径 B:内网离线环境用 deb 包升级

内网机器连不了外网的场景很常见。去 MySQL 官方下载页面把mysql-server、mysql-client、mysql-common、libmysqlclient*这几个 deb 包下载齐,放到同一目录下。然后有两种安装方式:

推荐用apt安装本地包,它会自动处理依赖:

sudo apt install ./mysql-server_8.0.36-1ubuntu22.04_amd64.deb

如果系统提示依赖缺失,先执行:

sudo apt-get -f install

修复依赖后再继续。

旧式做法是直接用dpkg手动安装,但我建议安装顺序按 common、client、server 来,因为mysql-server对前两者有硬依赖:

sudo dpkg -i mysql-common_*.deb mysql-client_*.deb mysql-server_*.deb

直接先敲dpkg -i mysql-server很容易提示缺依赖,然后就得再回头补齐。这个坑我在离线环境里踩过好几次,顺序对了能省十分钟。

3.3 路径 C:官方 tar.gz 二进制包原地替换

当初用官方二进制包手动部署到/usr/local/mysql的朋友,做小版本升级也不复杂,核心思路是:停服务、备份旧程序目录、替换 bin 和 lib、保留 datadir 和配置。完整命令:

systemctl stop mysql mv /usr/local/mysql /usr/local/mysql.bak_$(date +%F) tar -xf mysql-8.0.36-linux-glibc2.17-x86_64-minimal.tar.xz mv mysql-8.0.36-linux-glibc2.17-x86_64 /usr/local/mysql chown -R mysql:mysql /usr/local/mysql systemctl start mysql

有两个坑必须提醒。第一,不要把整个/usr/local/mysql目录rm -rf再解压新的,那样很容易连带删掉你自定义的路径配置、软链接和自定义插件。第二,替换完记得确认文件权限,我见过一次替换后mysqld文件变成了 644,启动直接报 Permission denied,最后chmod 755 /usr/local/mysql/bin/mysqld才解决。在乌班图上,权限问题是手动部署最常见的问题源,没有之一。

4. 乌班图执行升级时的几个魔鬼细节

4.1 用 apt-mark hold 防止被系统更新顺手带走

如果你平时会执行apt upgrade,升级完 MySQL 后一定要考虑把它 hold 住,否则哪天系统更新就把 MySQL 版本一起带跑了,既可能跳过你精心验证过的小版本,也可能引入新问题。

sudo apt-mark hold mysql-server mysql-client mysql-common

想恢复自动升级时再 unhold:

sudo apt-mark unhold mysql-server mysql-client mysql-common

这个操作不影响你手动做小版本升级,只是让你对版本有控制权。生产环境我基本都会建议 hold 住,等正式评估过再手动升。

4.2 systemd 单元文件和服务脚本混乱

乌班图 22.04 的 MySQL 8.0 一般都用 systemd 管理,systemctl restart mysql是很常规的操作。但如果这台机器是从 MySQL 5.7 一路升上来的老机器,可能还残留/etc/init.d/mysql这类 SysV 脚本,升级后服务启停有可能出现混乱。

遇到服务启动失败,别只盯着systemctl status mysql前面的几行,要看完整日志:

journalctl -u mysql -n 100

我遇到过升级后重启失败,日志里报Access denied for user 'debian-sys-maint'。这个用户是乌班图 mysql-server 包内部用来做日常维护的特殊账号,密码记录在/etc/mysql/debian.cnf里。升级后配置文件和 data 目录里实际账号不一致,就会反复报这个错。解决方法是核对/etc/mysql/debian.cnf里的账号和权限是否和数据目录一致,确认后重启服务。这是乌班图特有、但在网上很少被提及的经典坑。

4.3 mysql_upgrade 到底什么时候跑?千万别乱跑

关于mysql_upgrade,很多旧教程还在讲“升级完必须手动跑 mysql_upgrade”,但这里必须分清楚版本。MySQL 8.0.16 开始,mysqld 启动时会自动执行升级检查,不需要手动执行 mysql_upgrade 了。如果你拿旧教程对着 8.0.36 手动跑,运气好是多此一举,运气不好可能触发版本不匹配的报错。

如果你真的必须手动执行(比如从 8.0.15 或更早版本升级到新版本),请确保使用和当前二进制一致的mysql_upgrade程序:

mysql_upgrade -u root -p

而 8.0.16 之后的正常流程是:升级包之后第一次启动 mysqld,看 error log 里有没有类似Checking if update is needed的记录,这条记录说明自动升级流程已经启动。如果看到Upgrade process encounters error,必须立刻停下来查看完整日志,不要继续操作。

4.4 连接不上的典型报警:error 2003 到底怎么查

升级后最常收到的报警就是ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost:3306' (10061)。严格来说,这个错误表示客户端根本没有连到 MySQL 服务,可能是服务没启动、端口没监听、防火墙拦截或 socket 路径不一致。

排查的黄金组合命令:

systemctl status mysql ss -tlnp | grep 3306 mysql -u root -p -h 127.0.0.1 -P 3306 mysql -u root -p -S /var/run/mysqld/mysqld.sock

如果 3306 端口在监听,但 TCP 连不上,检查/etc/mysql/mysql.conf.d/mysqld.cnf里的bind-address和skip-networking配置。如果 socket 方式能连而 TCP 不能连,通常也是这两个配置项的问题。另外 MySQL 8.0 默认 root 账号使用的是caching_sha2_password认证插件,老版本客户端连接时可能会报unknown plugin 'caching_sha2_password',这时需要升级客户端版本,或者调整账号的认证插件。升级后连接相关问题,按这个顺序排查基本能覆盖 90% 的情况。

4.5 依赖库缺失:libaio1 和 libnuma1 不能少

在比较精简的乌班图上装 MySQL 8.0,很容易缺libaio1、libnuma1这些运行库,离线 deb 包升级时尤其常见。如果升级后 mysqld 启动失败,并且 error log 里提到缺少共享库,先把运行库补齐:

sudo apt-get install -y libaio1 libnuma1 libtinfo5

装完再启动服务。这个坑很小,但排查起来很烦人,经常被人忽略。

5. 主从/复制环境的小版本升级:顺序和执行窗口

5.1 为什么一定要先升从库

生产环境很少是单机,主从复制下的小版本升级讲究顺序。我的原则永远是:先升从库,观察没问题后,再升主库。如果从库升级后启动失败,主库仍然在跑旧版本,业务不受影响,回滚范围也被限制在从库。如果反过来先升主库,一旦新版本有问题,整个写入路径全挂在奇怪状态上,恢复成本直接翻倍。

5.2 升级前检查复制状态,别带延迟升级

动手升级之前,在主库上检查复制状态:

SHOW REPLICA STATUS\G

注意:MySQL 8.0.22 之后,命令从SHOW SLAVE STATUS改成了SHOW REPLICA STATUS。主要观察两个字段:Slave_IO_Running和Slave_SQL_Running是否都为Yes,Seconds_Behind_Master是否为0。如果从库还有大量延迟,我会先等它追平再做升级,避免在升级过程中出现复制通讯异常,排查起来特别麻烦。

5.3 一个真实的升级报警:Error reading packet from server

有一次我把从库从 8.0.35 升到 8.0.36,从库日志里出现了Error reading packet from server的报错。我一开始以为是补丁版本之间的协议差异,排查了很久,最后发现是主库在维护窗口里恰好有大事务 DDL,binlog 传输时旧连接断开重连,产生了瞬时告警。小版本升级时这种问题不常见,但遇到也别慌,通常重连就能恢复。我的建议是:升级窗口内,尽量不要同时跑大事务、大 DDL 或大批量写入任务。

5.4 完整执行顺序参考

如果条件允许,我一般按这个顺序操作:

  1. 从库升级:停服务、替换包、重启服务、看 error log。
  2. 从库验证通过后,持续观察一段时间,确认无复制报错。
  3. 主库升级前,先把业务写入降级或设置只读:
SET GLOBAL read_only = ON;
  1. 在主库做一次FLUSH TABLES WITH READ LOCK;,可选再做一次物理冷备。
  2. 按同样步骤升级主库并重启。
  3. 恢复read_only = OFF,观察主从状态是否恢复正常。

如果主库升级失败,优先用物理备份恢复,或者把旧二进制替换回去,千万不要试图去修改从库数据来匹配主库。那种操作一旦走错,整条复制链路都会废掉。

6. 升级后的验证清单与我最想提醒的一件事

6.1 验证版本和运行状态

升级完成不代表结束,验证才是重点。先确认版本号和运行状态:

mysql -u root -p -e "SELECT VERSION(); SHOW STATUS LIKE 'Uptime'; SHOW VARIABLES LIKE 'innodb_version';"

同时去看/var/log/mysql/error.log,确认日志末尾有ready for connections。这个日志是 MySQL 真正启动完成最可靠的标志。另外确认数据目录权限:

ls -ld /var/lib/mysql df -h /var/lib/mysql

如果权限意外变成 root,mysqld 会拒绝读取数据目录,启动即失败。修正时记得先停服务,再执行chown -R mysql:mysql /var/lib/mysql,然后启动。

6.2 数据完整性抽查与性能回检

升级前如果记录过关键表的 checksum,升级后直接对比最靠谱:

CHECKSUM TABLE db1.t_order, db2.t_user;

没有记录 checksum 也没关系,抽几张关键大表做SELECT COUNT(*),再随机抽样看几条数据是否正常。性能方面,观察慢查询日志有没有明显变慢,redo log 文件大小和 buffer pool 命中率有没有异常波动。小版本升级通常性能差异很小,如果出现明显的锁等待或大量慢查询,优先查看版本 release notes 里有没有已知问题。

6.3 我最想提醒的一件事:小版本升级不是越新越好

最后说一个很多人容易忽略的点:补丁版本不是越新越好。每次 MySQL 发布新补丁版,社区都会在短时间内反馈一些新问题,某些 8.0.x 在特定并发场景下表现反而不如旧版的现象也出现过。我的习惯是让目标版本先“飞”一段时间,等两到四周没有大规模负面反馈再升级。另外,别在乌班图系统源里同时混装 mysql-5.7 和 mysql-8.0 的仓库,apt 有时候会把 mysql-common 解析成另一个系列,导致版本互相覆盖。我见过一次升级后 mysql-common 被莫名替换成 5.7,整个包管理依赖一团乱,最后只能手动卸载重装。

小版本升级虽然动作小,但前面说的三件事:确认版本来源、做备份、记录环境快照,只要扎实做好了,剩下交给重启后的日志验证就行。服务器这东西,稳比新重要。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询