同一台机器启动多个mysqld进程的关键是彻底隔离各实例的配置、数据目录、端口和socket文件,每个实例须独立初始化datadir并使用专用systemd单元文件。

同一台机器启动多个 mysqld 进程的关键是隔离配置
MySQL 本身不支持“多实例”这个概念,所谓多实例,本质是运行多个独立的 mysqld 进程,每个进程加载自己的一套配置、数据目录和端口。最常踩的坑是直接复制 my.cnf 但没改 datadir、socket、port,导致启动失败或覆盖数据。
实操建议:
- 每个实例必须有独立的
datadir(如/var/lib/mysql801、/var/lib/mysql802),且目录属主为mysql用户 - 每个实例用不同端口:
port = 3307、port = 3308,避免Can't start server: Bind on TCP/IP port -
socket文件路径必须唯一,比如/tmp/mysql_3307.sock,否则客户端连错实例 - 推荐为每个实例准备单独的配置文件(如
/etc/my_3307.cnf),而不是在主配置里写多段[mysqld@instance1]
初始化多个数据目录不能复用 mysqld --initialize
第一次启动前,每个 datadir 都要单独初始化,否则会报 Failed to open log file 或直接拒绝启动。很多人以为初始化一次就能复制,但这样会导致所有实例共用同一套系统表空间、相同的 server-uuid,后续主从或 GTID 场景会彻底乱掉。
实操建议:
- 对每个实例分别执行:
mysqld --defaults-file=/etc/my_3307.cnf --initialize --user=mysql - 初始化后立即记录生成的临时密码(输出在 error log 里,不是终端),别等启动后再找
- 不要手动拷贝
mysql系统库目录——每个实例的mysql库都必须由自己的mysqld初始化生成 - 如果用 MySQL 8.0+,注意
--initialize默认启用强密码策略,若需空密码测试,加--initialize-insecure(仅限非生产)
用 systemd 管理多个实例时,服务名和 Unit 文件不能共用
直接 cp /usr/lib/systemd/system/mysqld.service /etc/systemd/system/mysqld@3307.service 是常见做法,但光改文件名不够:Unit 文件里的 ExecStart 必须指向对应配置,且 %i 占位符要正确使用,否则 systemctl start mysqld@3307 实际还是加载默认配置。
实操建议:
- Unit 文件中
ExecStart应明确指定配置:ExecStart=/usr/sbin/mysqld --defaults-file=/etc/my_%i.cnf - 确保
%i和实际服务名一致(如启动mysqld@3307,则配置文件必须叫/etc/my_3307.cnf) - 每次增删实例后运行
systemctl daemon-reload,否则新 service 不被识别 - 检查日志用
journalctl -u mysqld@3307 -n 50,别只看/var/log/mysqld.log——systemd 下日志默认走 journal
连接时指定 --port 或 --socket 才能连对实例
很多用户用 mysql -u root -p 连不上,其实是客户端默认连 localhost:3306,而新实例跑在 3307。更隐蔽的问题是:当 host = localhost 时,MySQL 客户端优先走 socket 文件,而不是 TCP;如果没配对 socket,就会连到别的实例甚至报 Can't connect to local MySQL server。
实操建议:
- 明确指定端口:
mysql -u root -p -P 3307(注意大写P) - 或指定 socket:
mysql -u root -p -S /tmp/mysql_3307.sock - 避免用
127.0.0.1当 host 测试——它强制走 TCP,掩盖 socket 配置问题;真要验证 socket 是否生效,就用localhost - 应用连接字符串里也得填对端口,别依赖中间件自动路由
真正麻烦的不是启动几个进程,而是每个实例的 server-id、log-bin、gtid_mode 等复制相关参数一旦重复或冲突,故障排查成本会指数级上升。上线前务必逐项核对 error log 开头的启动参数打印行。


















