Mac 上如何同时运行多个MySQL版本?

前言

由于我准备下载最新的 Redmine 6.0 版本到本地运行,所需的 MySql 版本要求为:8.0-8.1,且我打算保留本地已经在运行的 5.7 版本,不做干涉。

使用 Homebrew 下载 MySql8.0 版本

shell 复制代码
# 先搜索mysql版本
brew search mysql

# 搜索到就安装
brew install [email protected]

配置及初始化数据目录

正常安装好 MySql 后,会自动创建 MySql 的配置文件 my.cnf 及 数据目录,由于已经存在 5.7 版本,Homebrew 不会自动创建了。

5.7 版本的 my.cnf 配置文件如下:

shell 复制代码
# Default Homebrew MySQL server config
[mysqld]
# Only allow connections from localhost
bind-address = 127.0.0.1
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

这时直接启动 brew services start [email protected] 已经报失败了。如果看不到错误原因,可以使用 /opt/homebrew/opt/[email protected]/bin/mysqld --debug 来启动,这时已经有详细的错误原因了:

shell 复制代码
2025-01-23T10:00:42.390289Z 0 [ERROR] [MY-000077] [Server] /opt/homebrew/opt/[email protected]/bin/mysqld: Error while setting value 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' to 'sql_mode'.
2025-01-23T10:00:42.390320Z 0 [ERROR] [MY-010119] [Server] Aborting
2025-01-23T10:00:42.390550Z 0 [Note] [MY-010120] [Server] Binlog end

错误表明:于 5.7 配置文件中的 sql_mode 设置不兼容或某些选项在当前 8.0 版本中不支持导致的。

为什么会报这个错呢?因为 8.0 也是使用默认的 5.7 my.cnf 配置文件。

那好,接下来手动新建一个 8.0 配置文件,复制 /opt/homebrew/etc/my.cnf/opt/homebrew/etc/my80.cnf

my80.cnf 配置如下:

shell 复制代码
# Homebrew MySQL8.0 server config
[mysqld]

port=3307

# 数据目录
datadir=/opt/homebrew/var/mysql80new
socket=/opt/homebrew/var/mysql80new/mysql.sock

# 错误日志
log_error=/opt/homebrew/var/mysql80new/error.log

# 默认字符集
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

# Only allow connections from localhost
bind-address = 127.0.0.1

# SQL模式
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO

再次指定新的配置文件启动 8.0

shell 复制代码
# 使用 mysqld_safe 启动 MySQL,它会更安全地启动 MySQL,并记录更多调试信息
/opt/homebrew/opt/[email protected]/bin/mysqld_safe --defaults-file=/opt/homebrew/etc/my80.cnf

tail -f /opt/homebrew/var/mysql80new/error.log 查看日志果然又报错了

shell 复制代码
2025-01-23T23:36:45.925467Z 0 [System] [MY-010116] [Server] /opt/homebrew/opt/[email protected]/bin/mysqld (mysqld 8.0.39) starting as process 74975
2025-01-23T23:36:45.933475Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /opt/homebrew/var/mysql80/ is case insensitive
2025-01-23T23:36:45.946573Z 1 [ERROR] [MY-011011] [Server] Failed to find valid data directory.
2025-01-23T23:36:45.946727Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed.
2025-01-23T23:36:45.946740Z 0 [ERROR] [MY-010119] [Server] Aborting
2025-01-23T23:36:45.947616Z 0 [System] [MY-010910] [Server] /opt/homebrew/opt/[email protected]/bin/mysqld: Shutdown complete (mysqld 8.0.39)  Homebrew.
2025-01-23T23:36:45.6NZ mysqld_safe mysqld from pid file /opt/homebrew/var/mysql80/panfengdeMacBook-Pro.local.pid ended

错误原因是:Failed to find valid data directory,Data Dictionary initialization failed,表明:MySQL 没有找到有效的数据目录,启动时尝试初始化数据字典时失败了。

接下来就在启动的时候执行初始化:

shell 复制代码
/opt/homebrew/opt/[email protected]/bin/mysqld_safe --initialize --user=$(whoami) --datadir=/opt/homebrew/var/mysql80new --defaults-file=/opt/homebrew/etc/my80.cnf

又报错了:

shell 复制代码
2025-01-24T01:16:27.584805Z 0 [ERROR] [MY-000077] [Server] /opt/homebrew/opt/[email protected]/bin/mysqld: Error while setting value 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' to 'sql_mode'.
2025-01-24T01:16:27.585040Z 0 [ERROR] [MY-013236] [Server] The designated data directory /opt/homebrew/var/mysql is unusable. You can remove all files that the server added to it.
2025-01-24T01:16:27.585281Z 0 [ERROR] [MY-010119] [Server] Aborting
2025-01-24T01:16:27.586993Z 0 [Note] [MY-010120] [Server] Binlog end

很奇怪明明指定了配置文件及数据目录,怎么还是跑到 5.7 版本的位置去了?

经过查阅 MySql 8.0 文档得知:--defaults-file 选项必须要放在第一个选项才能生效。

好了,重新调整选项顺序执行:

shell 复制代码
/opt/homebrew/opt/[email protected]/bin/mysqld_safe --defaults-file=/opt/homebrew/etc/my80.cnf --initialize --user=$(whoami) --datadir=/opt/homebrew/var/mysql80new 

执行成功了,但是立马又退出了:

shell 复制代码
2025-01-24T03:04:10.172558Z 0 [System] [MY-013169] [Server] /opt/homebrew/opt/[email protected]/bin/mysqld (mysqld 8.0.39) initializing of server in progress as process 5416
2025-01-24T03:04:10.179400Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /opt/homebrew/var/mysql80new/ is case insensitive
2025-01-24T03:04:10.192972Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2025-01-24T03:04:10.326354Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2025-01-24T03:04:10.749031Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: ;jO?5puqH?(3
2025-01-24T03:04:11.082422Z 0 [System] [MY-013172] [Server] Received SHUTDOWN from user <via user signal>. Shutting down mysqld (Version: 8.0.39).

以上日志可以看到 MySql 已经启动成功了,且生成了临时 root 密码,但最后接受到 SIGTERM 信号从而中断了 MySql

加个 & 符号放在后台执行看看:

shell 复制代码
/opt/homebrew/opt/[email protected]/bin/mysqld --defaults-file=/opt/homebrew/etc/my80.cnf --datadir=/opt/homebrew/var/mysql80new --user=$(whoami) &

果然执行成功不会退出了。

尝试登录下 8.0MySql

复制代码
/opt/homebrew/opt/[email protected]/bin/mysql -uroot -p

输入临时密码:;jO?5puqH?(3 ,哦豁,登不上去,难道是要用引号转义?试一下:

shell 复制代码
/opt/homebrew/opt/[email protected]/bin/mysql -uroot -p';jO?5puqH?(3'
8.0版本已经不能直接把密码输在后面了,已经报错了:
[Warning] Using a password on the command line interface can be insecure.

或者 `/opt/homebrew/opt/[email protected]/bin/mysql -uroot -p 然后非明文输入,还是报密码不对。

试一下用 navicat 连下吧:

navicat 连成功了!

思考一下

再试一次用 5.7 的密码来连,这次指定了端口

shell 复制代码
 /opt/homebrew/opt/[email protected]/bin/mysql -uroot --port=3307 -p

居然连到 5.7 的版本上去了

shell 复制代码
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 26
Server version: 5.7.40 Homebrew

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql

为什么呢?

原因:MySql 客户端在连接时,会优先选择基于 socket 文件(在 UNIX 系统上)。当不指定 socket 文件时,MySql 客户端通常会默认使用系统中配置的标准值来进行连接。

navicat 为什么能正确连接呢?猜测 navicat 应该是读取并解析 MySql 配置文件中的 socket 参数。

当设置连接主机为 localhost 时,MySql 客户端库会直接使用 socket 文件来连接,而不是 TCP/IP。这是 MySql 客户端的默认行为,Navicat 通过调用 MySql 客户端库继承了这一特性。

如何解决?

连接的时候明确指定 socket

shell 复制代码
/opt/homebrew/opt/[email protected]/bin/mysql -uroot -p --port=3307 --socket=/opt/homebrew/var/mysql80new/mysql.sock

尝试使用 Homebrew 来正常启动 MySql8.0 版本

Homebrew 使用 LaunchAgents 来管理服务(如 MySql)。可以手动修改其 .plist 文件来指定 --defaults-file 或其他参数。

找到 [email protected]plist 文件路径

shell 复制代码
ls ~/Library/LaunchAgents | grep mysql

输出:

shell 复制代码
[email protected]

发现没有 8.0 版本的 plist,那么就复制从 5.7 复制一份到 8.0

shell 复制代码
cp ~/Library/LaunchAgents/[email protected] ~/Library/LaunchAgents/[email protected]

编辑如下:

shell 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>KeepAlive</key>
	<true/>
	<key>Label</key>
	<string>[email protected]</string>
	<key>LimitLoadToSessionType</key>
	<array>
		<string>Aqua</string>
		<string>Background</string>
		<string>LoginWindow</string>
		<string>StandardIO</string>
		<string>System</string>
	</array>
	<key>ProgramArguments</key>
	<array>
		<string>/opt/homebrew/opt/[email protected]/bin/mysqld</string>
		<string>--datadir=/opt/homebrew/var/mysql80new</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
	<key>WorkingDirectory</key>
	<string>/opt/homebrew/var/mysql80new</string>
</dict>
</plist>

使用 launchctl 启动下看看

shell 复制代码
launchctl load ~/Library/LaunchAgents/[email protected]

查看下进程是否启动成功了:

shell 复制代码
ps aux | grep mysqld

截图看可以看到能正常启动成功了,那我用 brew services start [email protected] 行不行?

先停止再启动

shell 复制代码
brew services stop [email protected]
brew services start [email protected]

发现问题了,停止后 8.0 的 plist 被清空了。

原因:Homebrew 使用 brew services 来管理服务时,会自动控制相关的 plist 文件的生成和加载。如果停止了 MySql 服务 (brew services stop [email protected]),Homebrew 并不会删除 plist 文件,当你再次启动服务时(brew services start [email protected]),它会重新生成并覆盖 plist 文件内容,因此,如果手动修改了 plist 文件,例如指定了自定义的 datadircnf 文件路径,这些修改会在重新启动时被覆盖,还是使用的 5.7 的配置。

为了防止意外使用 brew 来启动 8.0,复制一份 8.0的plist 到自定义的 plist

shell 复制代码
cp ~/Library/LaunchAgents/[email protected] ~/plist/mysql8.0-custom.plist

使用 launchctl 启动 8.0

shell 复制代码
launchctl load ~/mysql8.0-custom.plist

总结

目前尝试的有两种方式启动 MySql8.0

  1. 直接使用 mysqld 命令启动:
shell 复制代码
/opt/homebrew/opt/[email protected]/bin/mysql -uroot -p --port=3307 --socket=/opt/homebrew/var/mysql80new/mysql.sock
  1. 使用自定义的 plist 文件,使用 launchctl 启动
shell 复制代码
launchctl load ~/mysql8.0-custom.plist
相关推荐
天天摸鱼的java工程师7 小时前
高考放榜夜,系统别崩!聊聊查分系统怎么设计,三张表足以?
java·后端·mysql
Hello.Reader8 小时前
Git 安装全攻略Linux、macOS、Windows 与源码编译
linux·git·macos
exe4528 小时前
jdbc查询mysql数据库时,出现id顺序错误的情况
数据库·mysql
Hope Fancy8 小时前
macOS 连接 Docker 运行 postgres,使用navicat添加并关联数据库
macos·docker·postgresql
John Song8 小时前
macOS 上使用 Homebrew 安装redis-cli
数据库·redis·macos
yanjiee8 小时前
编译一个Mac M系列可以用的yuview
macos
数据知道8 小时前
Mac电脑上本地安装 redis并配置开启自启完整流程
数据库·redis·macos
Johny_Zhao9 小时前
阿里云数据库Inventory Hint技术分析
linux·mysql·信息安全·云计算·系统运维
loserkk10 小时前
MySQL InnoDB 5.7 索引失效场景解析:原理与案例
mysql
L.S.V.11 小时前
MYSQL(三)--服务器启动参数与配置
服务器·数据库·mysql