MySQL 5.7与8.0双版本共存部署实战指南

MySQL 5.7与8.0双版本共存部署实战指南

1. 项目概述:为什么需要在一台机器上共存两个MySQL版本?

做后端开发或者运维的朋友,可能都遇到过这个场景:线上生产环境还在跑着老版本的MySQL,比如经典的5.7,但新项目或者本地开发环境想尝鲜或者必须使用新特性,比如MySQL 8.0。直接升级线上数据库风险太大,重装系统又太折腾。这时候,最稳妥的办法就是在同一台机器上,让MySQL 5.7和8.0和平共处,各自监听不同的端口,互不干扰。

这听起来简单,但实际操作起来,从安装、配置到服务管理,每一步都有不少细节需要注意,稍有不慎就会导致端口冲突、服务无法启动,甚至把原有的数据库搞乱。我最近就因为项目需要,在自己的CentOS 7服务器上成功部署了MySQL 5.7和8.0的双版本环境,把整个流程和踩过的坑都梳理了一遍。这篇文章就是一份详细的实战记录,目标就是让你能照着步骤,安全、顺利地完成双版本MySQL的部署,无论是用于开发测试,还是作为生产环境的过渡方案。

2. 环境准备与核心思路拆解

在开始动手之前,我们必须把核心思路和准备工作做扎实。双版本共存的核心在于“隔离”,主要包括以下几个层面的隔离:

  1. 安装路径隔离:两个版本的MySQL必须安装在不同的目录下,绝对不能混用同一个/usr/local/mysql这样的默认路径。
  2. 数据目录隔离:各自的数据文件(如ibdata1,ib_logfile*, 以及各个数据库的文件夹)必须分开存放。
  3. 配置文件隔离:需要为每个版本准备独立的配置文件(如my.cnf),其中指定各自专用的端口、Socket文件路径、数据目录等关键参数。
  4. 服务进程与端口隔离:通过不同的端口号(如5.7用3306,8.0用3307)和Unix Socket文件来区分两个实例,确保它们能同时被客户端访问。
  5. 系统服务隔离:在Linux上,需要注册两个不同的系统服务(如mysqld5.7mysqld8.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/mysql8

3.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-files

3.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

写入以下内容,注意ExecStartExecStop的路径要指向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 mysqldsudo systemctl start mysqld8
停止服务sudo systemctl stop mysqldsudo systemctl stop mysqld8
重启服务sudo systemctl restart mysqldsudo systemctl restart mysqld8
查看状态sudo systemctl status mysqldsudo systemctl status mysqld8
设置开机自启sudo systemctl enable mysqldsudo systemctl enable mysqld8
禁用开机自启sudo systemctl disable mysqldsudo systemctl disable mysqld8
查看日志sudo tail -f /var/log/mysqld.log(路径可能不同)sudo tail -f /data/mysql8/error.log

4.3 常见问题与排查技巧实录

在实际操作中,你可能会遇到以下问题,这里给出排查思路:

问题1:MySQL 8.0服务启动失败,状态显示failed

  • 排查思路
    1. 首要查看错误日志:执行sudo journalctl -u mysqld8.service -xe或直接看我们配置的日志文件sudo tail -100 /data/mysql8/error.log。错误信息通常非常明确。
    2. 常见错误1:目录权限不足。确保/data/mysql8/usr/local/mysql8的所有者和所属组都是mysql,并且有正确的读写权限。用ls -la /data/mysql8检查。
    3. 常见错误2:端口被占用。检查3307端口是否被其他程序占用:sudo netstat -tlnp | grep 3307。如果被占用,要么停止那个程序,要么在/etc/my8.cnf中为MySQL 8.0换一个端口。
    4. 常见错误3:Socket文件路径冲突或权限问题。确保/data/mysql8目录存在且mysql用户有写权限,确保/etc/my8.cnfsocket配置的路径是准确的。
    5. 常见错误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。之后就可以用mysql5mysql8命令分别连接两个实例了。

问题4:想卸载其中一个版本,怎么办?

  • 安全卸载步骤
    1. 首先停止要卸载的服务:sudo systemctl stop mysqld8
    2. 禁用开机启动:sudo systemctl disable mysqld8
    3. 删除服务文件:sudo rm /etc/systemd/system/mysqld8.service
    4. 重新加载systemd:sudo systemctl daemon-reload
    5. (谨慎操作!)删除该版本的安装目录和数据目录:sudo rm -rf /usr/local/mysql8 /data/mysql8
    6. 删除该版本的配置文件: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.log

3. 备份策略差异化两个版本的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版本,核心思路都是相通的。