在Ubuntu上给MySQL做小版本升级,这件事看着小,翻车的方式却一点都不少。我见过有人直接在跑业务的库上解压新版二进制覆盖旧目录,也有人升级完数据库干脆启动不起来,最后发现是数据目录权限被改了。实际上小版本升级是MySQL日常运维里性价比非常高的操作:同一个大版本内的补丁升级,基本不需要改配置、不需要导出再导入数据,却能修复一堆已知的安全漏洞和bug。这篇文章就围绕乌班图上的MySQL小版本升级,把从环境检查、备份、升级执行、到回滚和排障的完整流程走一遍,覆盖apt官方仓库和二进制包两种最常见安装方式。不管你是刚接手生产库的新手,还是想给测试环境快速打补丁的老手,照着这个流程走基本不会出大问题。
1. 先搞清楚三个问题:版本、发行版、安装方式
1.1 小版本升级到底是什么,为什么值得做
MySQL的版本号可以拆成主版本.次版本.补丁版本三段,例如8.0.35中的8是主版本,0是次版本,35是补丁版本。所谓小版本升级,就是只让补丁版本递增,比如从8.0.34升到8.0.35,或者从5.7.43升到5.7.44。还有一种情况是次版本升级,比如从8.0升到8.4,但那是另一个量级的话题,今天不展开。
为什么小版本升级值得做?最主要的驱动力是安全和稳定性。几乎每个小版本都包含若干个安全漏洞修复,某些漏洞的利用门槛低到可以完全自动化扫描,不及时补版本等于敞着门跑业务。其次是bug修复,数据库崩溃、复制中断、查询计划异常这一类问题,很多都在后续小版本中修复。另外还有少量性能优化,虽然不会让整个库脱胎换骨,但积少成多。相比之下,升级成本非常低:同大版本内升级不改变表结构、存储格式和复制协议,正常情况下不需要导出数据再导入,也不需要重新初始化数据目录。
但低成本不等于零成本,这正是我要写这篇文章的原因。小版本升级真正要小心的不是SQL兼容性,而是操作手法:比如升级过程中磁盘空间不足、数据目录权限错乱、apt源和版本不匹配,还有最常见的“升级完发现跑的还是旧版本”。把流程做规范,风险可以低到忽略不计。
1.2 三种安装方式,三种升级路径
在讨论升级步骤之前,先判断你机器上的MySQL到底是怎么装的。因为不同安装方式对应的升级路径完全不同,这一步判断错,后面全白忙活。乌班图上常见的安装方式大致分三种,我直接整理成一张对照表:
| 判断维度 | Ubuntu自带apt源安装 | MySQL官方apt源安装 | 二进制tar包/源码安装 |
|---|---|---|---|
| 包管理跟踪 | dpkg可查,版本通常较旧 | dpkg可查,版本较新 | dpkg查不到 |
| 默认数据目录 | /var/lib/mysql | /var/lib/mysql | 自定义目录,如/data/mysql |
| 服务管理方式 | systemd | systemd | 可能是systemd,也可能是手动脚本 |
| 升级路径 | 换成官方源后apt upgrade | apt upgrade | 替换二进制目录 |
判断命令也很简单,先看版本和路径:
mysql --version which mysqld dpkg -S $(which mysqld)如果dpkg -S的输出类似“mysql-server-8.0: /usr/sbin/mysqld”,说明是dpkg管理的apt安装;如果提示“no path found matching pattern”,那基本就是二进制包或者源码安装。再用systemctl cat mysql看一眼Unit文件里的ExecStart路径,也能佐证。
还有一个比较反直觉的点:很多人以为自己在用apt升级,结果包管理器和实际运行版本对不上。比如二进制包装了8.0.36,apt里还装了一个8.0.32的mysql-server,两者互相干扰,systemctl status mysql显示的可能是任意一个。遇到这种情况,先明确想保留哪一套,把另一套彻底卸载掉,再继续升级,否则排查起来非常痛苦。
1.3 升级前的基本防线:低峰期与磁盘空间
无论哪种升级方式,都建议选在业务低峰期。apt升级大概率会触发MySQL服务重启,二进制包替换也会重启服务,哪怕只有几十秒的中断,对写密集业务都可能有影响。提前和团队打声招呼,或者干脆在凌晨操作,避免事故扩大。
磁盘空间检查也必不可少。备份文件、新版本二进制、旧的二进制包,算下来可能要占好几个GB。df -h看根分区的时候不用只看剩余空间,还要看/var、/usr挂载点是否单独分区,别等备份写到一半报No space left on device,那才是最被动的时刻。
2. 升级之前,把备份和回滚方案做扎实
2.1 环境信息记录清单
升级前花五分钟记录以下信息:当前版本、数据目录、配置文件、服务启停方式、磁盘空间。用一行命令可以把它们存成文件,后续回滚时直接翻文件就行:
mysql --version > /backup/pre_upgrade_info_$(date +%F).txt cat /etc/mysql/my.cnf >> /backup/pre_upgrade_info_$(date +%F).txt systemctl cat mysql >> /backup/pre_upgrade_info_$(date +%F).txt df -h >> /backup/pre_upgrade_info_$(date +%F).txt别小看这份记录。很多事故真正发生的时候,管理员连数据目录在哪都要现找,有了这份备份,回滚路径会清晰很多。
2.2 逻辑备份:mysqldump怎么用才靠谱
备份我推荐先用mysqldump把逻辑数据导出,这是一个迁移性最强的备份形式,既能用于升级回滚,也能用于跨机器恢复。推荐参数组合:
mysqldump -u root -p \ --all-databases \ --single-transaction \ --routines \ --triggers \ --events \ --master-data=2 \ --hex-blob \ > /backup/mysql_full_$(date +%F).sql参数逐个说一下:--single-transaction对InnoDB引擎采用一致性快照,备份过程中不锁表、不阻塞业务读写;但注意它只对InnoDB事务引擎有效,如果库里有大量MyISAM表,要配合--lock-all-tables使用,生产环境一般以InnoDB为主,问题不大。--routines、--triggers、--events这几个参数特别容易被漏掉,存储过程、触发器、事件调度器默认不导出,漏掉会导致业务恢复后缺一堆逻辑。--master-data=2会把二进制日志位置写进备份文件,方便做主从定位。--hex-blob把二进制字段以十六进制导出,防止字符集转换出问题。
备份完成后必须验证,否则等于没备份。最简单的验证方法是看文件大小和内容:
ls -lh /backup/mysql_full_$(date +%F).sql grep -c '^CREATE TABLE' /backup/mysql_full_$(date +%F).sql文件大小合理、CREATE TABLE数量对得上,这份备份才基本可信。
2.3 物理备份:数据目录快照
逻辑备份虽好,恢复时要把全部数据重新导入一次,几GB甚至几十GB的数据导入非常慢。如果数据量大,建议再做一份物理备份。做法很直接:先停MySQL,然后把整个数据目录打包。
sudo systemctl stop mysql sudo tar czvf /backup/mysql_datadir_$(date +%F).tar.gz /var/lib/mysql sudo systemctl start mysql这里有个关键点:打包必须在MySQL完全停止的状态下进行。很多人图省事,跑着服务直接cp数据目录,结果数据文件处于不一致状态,备份等于废的。如果数据目录特别大,这一步耗时可能很长,要预留足够时间窗。打包完成后,顺手把/backup目录挂载点、剩余空间再确认一遍。
2.4 回滚预案怎么写
备份做完,顺手把回滚预案写下来。其实小版本升级的回滚逻辑很简单:把旧二进制(或旧包)和备份数据目录放回去,再启动服务。但如果你从来没记录过数据目录在哪、配置文件怎么改的,出事那一刻才想起来查,就会非常被动。我习惯把升级前版本号、包名、数据目录大小、下一步回滚用到的命令都写进一个文本文件,跟着备份放一起。这个习惯救过我很多次,熟手一样需要,不是只有新手才该列预案。
3. 方案一:apt官方仓库升级,最省心的路线
3.1 添加MySQL官方apt源并更新
Ubuntu系统自带的源里MySQL版本通常比较旧,而且跟着Ubuntu LTS的更新节奏走,往往落后好几个小版本。如果你当前MySQL是通过官方deb源装的,升级只需要apt update之后再apt upgrade。如果机器上用的还是Ubuntu自带源,建议先加官方源,这样才能拿到更新更及时的补丁版本。
具体操作是先从官网下载mysql-apt-config包,我用的是Ubuntu 22.04,20.04同样适用:
wget https://dev.mysql.com/get/mysql-apt-config_0.8.33-1_all.deb sudo dpkg -i mysql-apt-config_0.8.33-1_all.debdpkg执行后会弹出选择界面,把MySQL Server & Cluster保持默认即可,也可以选择指定系列更新。然后执行apt update:
sudo apt updateapt update正常后,用下面的命令查看是否有MySQL相关的新版本:
sudo apt list --upgradable | grep mysql如果列表里的mysql-server还是旧版,检查一下源文件是否处于激活状态,或者把/etc/apt/sources.list.d/mysql.list里的内容贴出来核对一遍。顺便说一下,这个方案对比纯二进制替换的优点是:升级后版本由apt跟踪,以后每个小版本都能及时看到,不会再出现“库跑了半年也不知道升级到哪了”的情况。
3.2 执行升级,要精准不要地毯式
升级命令就一句话,但注意别用sudo apt upgrade无差别升级全系统。生产环境最忌讳顺手把无关包一起升级,你只想升级MySQL,就指定包名:
sudo apt install --only-upgrade mysql-server mysql-client mysql-community-server mysql-community-client如果当前就是官方源安装的MySQL,执行完这条命令apt会自动处理依赖并触发服务重启。如果之前是Ubuntu自带源安装的MySQL,想要切到官方源并升级,通常会遇到包名冲突或版本优先级问题。我的经验是先dpkg -l | grep mysql梳理当前安装的包,再决定是用替换方式还是卸载重装。这个场景有一定风险,建议备份完再操作,不要在生产环境裸切源。
升级过程中apt会提示服务重启,选择yes即可。这一步开始,MySQL服务会被重启,连接会短暂中断。升级完成后,mysql --version看到的应该就是新版本号。
3.3 升级后检查清单
升级完成别急着走,按这个清单逐项确认:
systemctl status mysql mysql -u root -p -e "SELECT VERSION();" tail -n 50 /var/log/mysql/error.log状态是active (running)、版本号符合预期、日志里没有[ERROR],基本就稳了。再跑几条常用查询对比执行时间,确认没有明显的性能回退。
这里我要提醒一个容易忽略的点:MySQL 8.0小版本升级后,通常不需要手动执行mysql_upgrade,官方会在服务启动时自动检查元数据版本。但如果你是从非常老的小版本一次性跨很远的升级,比如8.0.11直接升8.0.36,建议还是看一遍官方Release Notes,确认是否要求手动执行。另外,升级后观察几天再清理/var/cache/apt/archives里的旧包,这样万一要回滚还能找到旧deb文件。
4. 方案二:二进制包整体替换,自定义安装的稳妥路线
4.1 下载前先确认架构与glibc版本
如果你当初是解压tar包安装的,dpkg看不到MySQL,apt升级也就无从谈起。这种情况下,小版本升级等于把旧的二进制目录换成新的,数据目录原封不动。
下载之前需要确认三件事情:当前系统架构、glibc版本、当前MySQL大版本。命令如下:
uname -m ldd --version | head -1 mysql --versionx86_64架构通常选择linux-glibc2.28或linux-glibc2.17的包,aarch64架构要选对应的arm版本。然后到MySQL官网选择与当前主版本一致的最新补丁版本,例如:
wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz sha256sum mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz注意URL中的8.0.36只是举例,实际版本以官网当前提供为准,下载前花两分钟看一遍Release Notes,确认你需要的修复包含在目标版本里。SHA256校验一定要做,防止下载过程文件损坏,同时确认拿到的是官方完整包。
4.2 停服务、换二进制、保数据目录
假设MySQL装在/usr/local/mysql,数据目录在/data/mysql,配置文件在/etc/my.cnf。整个替换过程可以分为四步:
第一步,停止服务:
sudo systemctl stop mysql如果没有systemd服务脚本,就执行service mysql stop,或者找到原先的启动脚本手动停。
第二步,保留旧二进制。把旧目录改名而不是删除,这是回滚的底气:
sudo mv /usr/local/mysql /usr/local/mysql-8.0.36.bak第三步,解压新包并放到原路径:
sudo tar xf mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz -C /usr/local sudo mv /usr/local/mysql-8.0.36-linux-glibc2.28-x86_64 /usr/local/mysql第四步,修复属主:
sudo chown -R mysql:mysql /usr/local/mysql sudo chown -R mysql:mysql /data/mysql必须强调:不要在新目录里执行mysqld --initialize,那只会生成一个全新的空数据目录。数据一直在/data/mysql里,换成新二进制直接启动即可。关于这一点我反复说,因为它发生过太多次了,很多人下意识觉得“换了二进制就要初始化”,结果把已有数据目录覆盖成空白,那是真正的事故。
4.3 启动服务并核对版本
替换完成后,先别急着连数据库,直接启动并看日志:
sudo systemctl start mysql sudo journalctl -u mysql -n 80没有报错再验证版本:
mysql -u root -p -e "SELECT VERSION();"如果启动失败,看日志里有没有提到参数不识别、目录不存在、权限不足。新版本对旧配置文件的容忍度总体不错,但个别参数在新版本中被移除了,会明确报unknown variable,在my.cnf里删掉即可。我建议第一次启动前把socket和pid文件路径再核对一遍,确保和客户端的默认路径一致。常见错误是客户端默认找/var/run/mysqld/mysqld.sock,但新二进制配置成了别的路径,导致连接失败。
5. 常见问题与故障排查实录
5.1 服务启动失败:先看日志,再动手
升级后最典型的报错是服务起不来。遇到频率从高到低排序大概是:依赖库缺失、数据目录权限错误、配置文件参数不识别、socket目录不存在。第一时间看日志再处理,MySQL会把关键错误写进error log或者journald,不看日志直接瞎猜只会浪费时间。
| 现象 | 常见原因 | 解决方式 |
|---|---|---|
| 启动失败,提示libaio相关错误 | 缺libaio | sudo apt install libaio1 |
| 启动失败,提示数据目录无法访问 | 数据目录属主变了 | sudo chown -R mysql:mysql /var/lib/mysql |
| Can't connect to local MySQL server through socket | 服务没启动或socket路径不一致 | 先看状态与日志,确认socket路径 |
| /var/run/mysqld目录不存在 | 目录异常 | 创建目录并chown mysql:mysql |
| unknown variable xxx | 配置参数在新版本中移除 | 在my.cnf中删除该参数 |
5.2 apt源问题:GPG密钥过期和版本不更新
apt update时出现NO_PUBKEY,很多人一慌就换源,其实最常见原因是MySQL官方仓库的GPG key过期,重新获取一下就行:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys <KEY_ID> sudo apt updateapt-key在较新的Ubuntu版本上会有deprecation警告,但依然可用;更标准的做法是下载官方gpg key文件,用gpg --dearmor转换为ascr格式并放到/etc/apt/keyrings/,然后在源文件里用signed-by=/etc/apt/keyrings/mysql.gpg引用。生产环境建议尽早切到标准方式。
版本不更新还有一种情况:Ubuntu自带源和你新增的官方源同时存在,apt默认选了旧源。可以用sudo apt-cache policy mysql-server查看各候选版本与来源,确认官方源排在更前面。如果不想靠pin机制处理,直接把Ubuntu自带的mysql相关源注释掉,保持单一来源,简单直接。
5.3 升级后的稳定性观察与收尾
升级完不是看版本号对就算结束。我习惯保留一周的观察期,重点看两条线:error log里是否持续出现告警,慢查询指标和主从状态是否正常。MySQL 8.0某些参数默认值在小版本更新中会调整,比如和InnoDB自适应参数相关的行为,生产环境要观察内存和IO变化是否异常。
如果升级后确认一切正常,再处理旧版本的残留包和备份文件。旧二进制目录至少保留一周以上,备份文件至少要等到库上跑过几轮业务验证没问题再考虑清理。生产运维里最忌讳“升级完马上删备份”,真出问题的时候,备份就是最后的救命稻草。
最后说说我的个人习惯。这些年给各种环境做MySQL小版本升级,我总结下来最有效的三件事:升级前把环境信息和备份全部落到文件,升级中只用一条命令反复核对版本,升级后至少观察一周再清理旧东西。小版本升级的命令本身不复杂,真正考验人的是你有没有想清楚“出问题怎么办”这五个字。如果你在乌班图上维护的MySQL也一直停在旧版本,建议挑个低峰期,按这篇文章的流程做一次规范化升级,给自己省掉后面一堆未知的坑。