1. 项目概述:为什么需要在一台机器上共存两个MySQL版本?
做后端开发或者运维的朋友,可能都遇到过这个场景:线上生产环境还在跑着老版本的MySQL,比如经典的5.7,但新项目或者本地开发环境想尝鲜或者必须使用新特性,比如MySQL 8.0。直接升级线上数据库风险太大,重装系统又太折腾。这时候,最稳妥的办法就是在同一台机器上,让MySQL 5.7和8.0和平共处,各自监听不同的端口,互不干扰。
这听起来简单,但实际操作起来,从安装、配置到服务管理,每一步都有不少细节需要注意,稍有不慎就会导致端口冲突、服务无法启动,甚至把原有的数据库搞乱。我最近就因为项目需要,在自己的CentOS 7服务器上成功部署了MySQL 5.7和8.0的双版本环境,把整个流程和踩过的坑都梳理了一遍。这篇文章就是一份详细的实战记录,目标就是让你能照着步骤,安全、顺利地完成双版本MySQL的部署,无论是用于开发测试,还是作为生产环境的过渡方案。
2. 环境准备与核心思路拆解
在开始动手之前,我们必须把核心思路和准备工作做扎实。双版本共存的核心在于“隔离”,主要包括以下几个层面的隔离:
- 安装路径隔离:两个版本的MySQL必须安装在不同的目录下,绝对不能混用同一个
/usr/local/mysql这样的默认路径。 - 数据目录隔离:各自的数据文件(如
ibdata1,ib_logfile*, 以及各个数据库的文件夹)必须分开存放。 - 配置文件隔离:需要为每个版本准备独立的配置文件(如
my.cnf),其中指定各自专用的端口、Socket文件路径、数据目录等关键参数。 - 服务进程与端口隔离:通过不同的端口号(如5.7用3306,8.0用3307)和Unix Socket文件来区分两个实例,确保它们能同时被客户端访问。
- 系统服务隔离:在Linux上,需要注册两个不同的系统服务(如
mysqld5.7和mysqld8.0),方便独立管理启动、停止和状态查看。
基于这个思路,我们的操作流程可以概括为:先确保原有5.7稳定运行并记录其配置 -> 为8.0版本规划全新的安装和数据目录 -> 分别进行初始化、配置和服务注册 -> 最后进行连接测试和基础优化。在整个过程中,绝对不要动原有5.7版本的数据目录和正在使用的配置文件,这是保证生产环境安全的第一原则。
注意:本文以Linux系统(CentOS 7/8, Rocky Linux等)为例进行演示,使用二进制压缩包(TAR Archive)的方式安装,这种方式最灵活,也最适合多版本共存。Windows或macOS的思路类似,但具体路径和命令会有差异。
3. 详细实操步骤:从规划到安装配置
3.1 步骤一:检查与记录现有MySQL 5.7环境
在安装新版本之前,我们必须对现有环境了如指掌。首先,登录你的服务器,执行以下命令:
# 1. 检查当前MySQL 5.7的运行状态和版本 systemctl status mysqld mysql -V # 2. 查看当前MySQL使用的配置文件路径 # MySQL会按顺序读取多个位置的my.cnf,使用以下命令查看最终生效的配置 mysql --help | grep -A 1 -B 1 "Default options" # 通常,配置文件可能在 /etc/my.cnf, /etc/mysql/my.cnf, /usr/local/mysql/etc/my.cnf 等位置 # 使用以下命令查看具体加载了哪些文件 ps aux | grep mysqld | grep -v grep # 在输出中寻找 `--defaults-file=` 或 `--defaults-extra-file=` 参数,这指明了配置文件。 # 3. 记录关键参数 # 连接到MySQL 5.7实例 mysql -u root -p进入MySQL命令行后,执行以下SQL,将输出结果保存下来:
SHOW VARIABLES LIKE 'port'; SHOW VARIABLES LIKE 'socket'; SHOW VARIABLES LIKE 'datadir'; SHOW VARIABLES LIKE 'basedir';记下这些值,尤其是port(通常是3306)、datadir(数据目录,如/var/lib/mysql)和socket文件路径(如/var/lib/mysql/mysql.sock)。这能帮助我们避免与8.0版本产生冲突。
3.2 步骤二:为MySQL 8.0规划与创建专属目录
假设我们计划将MySQL 8.0安装到/usr/local/mysql8,数据存放在/data/mysql8。你需要根据磁盘空间情况自行调整。
# 创建安装目录和数据目录 sudo mkdir -p /usr/local/mysql8 sudo mkdir -p /data/mysql8 # 创建mysql用户和组(如果已有mysql用户,可跳过,但建议检查) sudo groupadd mysql sudo useradd -r -g mysql -s /bin/false mysql # 将数据目录的所有权赋予mysql用户 sudo chown -R mysql:mysql /data/mysql8 sudo chmod -R 750 /data/mysql83.3 步骤三:下载并安装MySQL 8.0二进制包
前往MySQL官方网站下载对应你系统架构(通常是x86_64)的二进制压缩包(TAR Archive)。建议使用国内镜像或确保网络通畅。
# 进入一个临时目录,例如 /tmp cd /tmp # 使用wget下载,请替换为实际的下载链接 # 例如:wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz # 这里以8.0.36为例,请下载最新或所需版本 wget [你的MySQL 8.0 TAR包下载链接] # 解压压缩包 tar -xvf mysql-8.0.*-linux-glibc2.17-x86_64.tar.xz # 将解压后的内容移动到我们规划的安装目录 sudo mv mysql-8.0.*-linux-glibc2.17-x86_64/* /usr/local/mysql8/ # 进入安装目录,创建mysql-files目录(用于安全文件操作) cd /usr/local/mysql8 sudo mkdir mysql-files sudo chown mysql:mysql mysql-files sudo chmod 750 mysql-files3.4 步骤四:准备MySQL 8.0的独立配置文件
这是最关键的一步,配置错误直接导致服务启动失败。我们需要为8.0创建一个全新的配置文件,例如/etc/my8.cnf。
sudo vim /etc/my8.cnf将以下配置内容写入文件。请务必根据你的实际情况修改port,socket,datadir,basedir,log-error等路径,并确保与5.7的配置不冲突。
[client] port=3307 socket=/data/mysql8/mysql.sock [mysql] default-character-set=utf8mb4 [mysqld] # 基础设置 user=mysql port=3307 socket=/data/mysql8/mysql.sock basedir=/usr/local/mysql8 datadir=/data/mysql8 log-error=/data/mysql8/error.log pid-file=/data/mysql8/mysql.pid # 网络与连接 bind-address=0.0.0.0 max_connections=200 character-set-server=utf8mb4 collation-server=utf8mb4_0900_ai_ci default_authentication_plugin=mysql_native_password # 文件路径 tmpdir=/tmp lc-messages-dir=/usr/local/mysql8/share # InnoDB设置 innodb_buffer_pool_size=256M innodb_log_file_size=48M innodb_flush_log_at_trx_commit=1 innodb_lock_wait_timeout=50 # 安全与兼容性(重要!) # 禁用符号链接,避免安全问题 symbolic-links=0 # 8.0默认的密码认证方式可能较老客户端不兼容,此项可确保兼容性 default_authentication_plugin=mysql_native_password # 关闭表名大小写敏感(根据习惯设置) lower_case_table_names=1 # 二进制日志(如需) # server-id=2 # log-bin=/data/mysql8/mysql-bin # expire_logs_days=7保存并退出。这个配置文件明确指定了8.0实例使用3307端口,Socket和数据文件都在/data/mysql8下,与5.7的3306和/var/lib/mysql完全隔离。
3.5 步骤五:初始化MySQL 8.0数据目录
MySQL 8.0的初始化命令与5.7略有不同,且更加严格。我们使用--defaults-file指定刚创建的配置文件。
# 确保在mysql用户下操作相关目录权限 sudo chown -R mysql:mysql /usr/local/mysql8 sudo chown -R mysql:mysql /data/mysql8 # 执行初始化,使用 --initialize-insecure 或 --initialize # --initialize-insecure: 初始化后root用户密码为空(仅用于测试,生产环境勿用) # --initialize: 初始化后会在error log中生成一个随机root密码 cd /usr/local/mysql8 sudo bin/mysqld --defaults-file=/etc/my8.cnf --initialize-insecure --user=mysql重要选择解释:这里我用了--initialize-insecure,因为这是搭建测试/开发环境,图个方便,初始化后root密码为空。如果是生产环境,强烈建议使用--initialize,然后去/data/mysql8/error.log里找到生成的临时密码。执行成功后,/data/mysql8目录下会生成完整的系统数据库文件。
3.6 步骤六:启动MySQL 8.0实例并进行安全设置
初始化完成后,我们可以首次启动这个8.0实例。由于还没有注册为系统服务,我们手动启动。
# 使用指定的配置文件启动MySQL 8.0 sudo /usr/local/mysql8/bin/mysqld_safe --defaults-file=/etc/my8.cnf --user=mysql & # 使用mysql客户端连接,注意指定端口和socket # 因为密码为空,直接回车 sudo /usr/local/mysql8/bin/mysql -u root -p --port=3307 --socket=/data/mysql8/mysql.sock成功连接后,你就进入了MySQL 8.0的命令行。接下来,必须立即修改root密码并执行一些安全设置,即使是在内网环境。
-- 修改root用户密码 ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPassword8@'; FLUSH PRIVILEGES; -- 可选:创建远程访问用户(按需) CREATE USER 'remote_user'@'%' IDENTIFIED BY 'RemoteUserPass8@'; GRANT ALL PRIVILEGES ON *.* TO 'remote_user'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES; -- 退出 exit;修改密码后,下次连接就需要使用新密码了。
3.7 步骤七:将MySQL 8.0注册为系统服务
手动启动毕竟不方便,我们需要像管理5.7一样使用systemctl来管理8.0。这需要创建一个新的service文件。
sudo vim /etc/systemd/system/mysqld8.service写入以下内容,注意ExecStart和ExecStop的路径要指向8.0的安装目录,并指定专用的配置文件。
[Unit] Description=MySQL Server 8.0 After=network.target After=syslog.target [Install] WantedBy=multi-user.target [Service] User=mysql Group=mysql Type=forking # 启动命令 ExecStart=/usr/local/mysql8/bin/mysqld_safe --defaults-file=/etc/my8.cnf # 停止命令(使用mysqladmin) ExecStop=/usr/local/mysql8/bin/mysqladmin -S /data/mysql8/mysql.sock -u root -p shutdown # 给服务足够的启动和停止时间 TimeoutSec=300 # 重启策略 Restart=on-failure RestartPreventExitStatus=1 PrivateTmp=true保存后,重新加载systemd并启用服务。
sudo systemctl daemon-reload sudo systemctl enable mysqld8.service # 停止之前手动启动的进程(如果还在运行) sudo pkill -f "mysqld.*my8.cnf" # 使用systemctl启动服务 sudo systemctl start mysqld8.service sudo systemctl status mysqld8.service如果状态显示为active (running),恭喜你,MySQL 8.0服务已经成功安装并运行了!现在你可以用sudo systemctl start/stop/restart mysqld8来管理它,用sudo systemctl status mysqld8查看状态。
4. 连接测试、日常管理与问题排查
4.1 双版本连接测试
现在你的机器上同时运行着两个MySQL实例。如何区分连接它们呢?关键在于指定正确的端口或Socket文件。
连接MySQL 5.7(默认端口3306):
mysql -u root -p -P 3306 -h 127.0.0.1 # 或者使用本地socket(如果客户端配置了默认socket) mysql -u root -p连接MySQL 8.0(我们设置的端口3307):
mysql -u root -p -P 3307 -h 127.0.0.1 # 或者使用我们指定的socket文件 mysql -u root -p -S /data/mysql8/mysql.sock
你可以在两个客户端窗口分别执行SELECT VERSION();来验证,一个会返回5.7.x,另一个返回8.0.x。
4.2 日常管理命令汇总
为了方便,我把管理两个服务的常用命令总结一下:
| 操作 | MySQL 5.7 (服务名通常为mysqld) | MySQL 8.0 (服务名我们设为mysqld8) |
|---|---|---|
| 启动服务 | sudo systemctl start mysqld | sudo systemctl start mysqld8 |
| 停止服务 | sudo systemctl stop mysqld | sudo systemctl stop mysqld8 |
| 重启服务 | sudo systemctl restart mysqld | sudo systemctl restart mysqld8 |
| 查看状态 | sudo systemctl status mysqld | sudo systemctl status mysqld8 |
| 设置开机自启 | sudo systemctl enable mysqld | sudo systemctl enable mysqld8 |
| 禁用开机自启 | sudo systemctl disable mysqld | sudo systemctl disable mysqld8 |
| 查看日志 | sudo tail -f /var/log/mysqld.log(路径可能不同) | sudo tail -f /data/mysql8/error.log |
4.3 常见问题与排查技巧实录
在实际操作中,你可能会遇到以下问题,这里给出排查思路:
问题1:MySQL 8.0服务启动失败,状态显示failed。
- 排查思路:
- 首要查看错误日志:执行
sudo journalctl -u mysqld8.service -xe或直接看我们配置的日志文件sudo tail -100 /data/mysql8/error.log。错误信息通常非常明确。 - 常见错误1:目录权限不足。确保
/data/mysql8和/usr/local/mysql8的所有者和所属组都是mysql,并且有正确的读写权限。用ls -la /data/mysql8检查。 - 常见错误2:端口被占用。检查3307端口是否被其他程序占用:
sudo netstat -tlnp | grep 3307。如果被占用,要么停止那个程序,要么在/etc/my8.cnf中为MySQL 8.0换一个端口。 - 常见错误3:Socket文件路径冲突或权限问题。确保
/data/mysql8目录存在且mysql用户有写权限,确保/etc/my8.cnf中socket配置的路径是准确的。 - 常见错误4:配置文件语法错误。仔细检查
/etc/my8.cnf,是否有拼写错误,特别是[mysqld]等节标题是否正确。
- 首要查看错误日志:执行
问题2:使用mysql客户端连接8.0时,报错“ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded”。
- 原因与解决:这是MySQL 8.0默认使用了更强的密码认证插件
caching_sha2_password,一些老的客户端或驱动不支持。我们在配置文件中已经通过default_authentication_plugin=mysql_native_password强制使用了旧的认证方式。如果还出现,可以在MySQL 8.0中修改相应用户的认证插件:ALTER USER '你的用户名'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; FLUSH PRIVILEGES;
问题3:如何区分两个版本的命令行工具?
- 解决方案:为两个版本创建别名或使用绝对路径。
- 在
~/.bashrc中添加别名:alias mysql5='/usr/bin/mysql' # 假设5.7的客户端在/usr/bin下 alias mysql8='/usr/local/mysql8/bin/mysql --defaults-file=/etc/my8.cnf' - 然后执行
source ~/.bashrc。之后就可以用mysql5和mysql8命令分别连接两个实例了。
- 在
问题4:想卸载其中一个版本,怎么办?
- 安全卸载步骤:
- 首先停止要卸载的服务:
sudo systemctl stop mysqld8。 - 禁用开机启动:
sudo systemctl disable mysqld8。 - 删除服务文件:
sudo rm /etc/systemd/system/mysqld8.service。 - 重新加载systemd:
sudo systemctl daemon-reload。 - (谨慎操作!)删除该版本的安装目录和数据目录:
sudo rm -rf /usr/local/mysql8 /data/mysql8。 - 删除该版本的配置文件:
sudo rm /etc/my8.cnf。
- 切记:删除数据目录(
/data/mysql8)意味着该实例的所有数据库都将永久丢失,操作前务必确认已备份重要数据!
- 首先停止要卸载的服务:
5. 进阶配置与性能调优考虑
双版本环境搭建好后,如果用于开发测试,基础配置已经足够。但如果负载稍高,或者希望更精细化控制,可以考虑以下方面:
1. 资源隔离与限制为了避免两个实例争夺系统资源(CPU、内存、磁盘IO),可以在各自的my.cnf中进行限制。
- 内存:
innodb_buffer_pool_size是InnoDB最重要的参数,应根据机器总内存合理分配。例如,机器有16G内存,5.7分配4G,8.0分配4G,给系统和其他应用留出余地。 - 连接数:通过
max_connections控制每个实例的最大并发连接数,防止一个实例耗尽所有连接资源。
2. 监控与日志分离确保两个实例的日志文件(错误日志、慢查询日志、通用日志)路径不同,便于排查问题。
# 在 /etc/my8.cnf 的 [mysqld] 节添加 slow_query_log=1 slow_query_log_file=/data/mysql8/slow.log long_query_time=2 general_log=0 # 生产环境建议关闭通用日志,否则日志量巨大 general_log_file=/data/mysql8/general.log3. 备份策略差异化两个版本的mysqldump工具最好使用各自版本的,避免兼容性问题。制定备份脚本时,要指定正确的端口、Socket和客户端路径。
# 备份MySQL 5.7 /usr/bin/mysqldump -u root -p -P 3306 --all-databases > backup_5.7.sql # 备份MySQL 8.0 /usr/local/mysql8/bin/mysqldump -u root -p -P 3307 --all-databases > backup_8.0.sql整个流程走下来,最深的体会就是“规划先行,隔离为王”。在操作前,花十分钟画个简单的目录和端口规划图,能避免后面一大堆的麻烦。尤其是配置文件和数据目录的路径,一旦弄混,排查起来相当头疼。另外,善用--defaults-file参数和systemctl status查看日志,是解决服务启动问题的两大法宝。这套方法不仅适用于5.7和8.0,理论上也适用于任何两个你想共存的MySQL版本,核心思路都是相通的。