恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
MySQL多实例安装与systemd开机自启配置完整指南
首页
资讯中心
/
MySQL多实例安装与systemd开机自启配置完整指南
MySQL多实例安装与systemd开机自启配置完整指南
发布时间:2026/10/22 6:05:19
有时候一个服务器上不得不跑多个 MySQL 实例。比如公司预算有限几套业务共用一个物理机比如开发、测试、预发环境想隔离但机器不够再比如你接手了一台跑了好几年的老机器上面已经有一个 3306 的实例在用新业务只能再塞一个 3307 进去。我这些年装过多实例踩过不少坑也总结了一套比较顺手的流程。这篇文章就把 MySQL 多实例安装和开机自启这件事从目录规划到 systemd 配置完整走一遍。适合刚入行两三年、需要自己动手搭环境的运维和开发同学也适合正在准备容器化改造但暂时还得靠物理多实例过渡的团队。全文基于最常见的二进制安装包方式不牵扯云厂商 RDS 之类的托管服务。1. 多实例的设计思路先想清楚再动手1.1 多实例到底解决什么问题多实例简单说就是在同一台 Linux 服务器上用独立的配置文件、独立的数据目录、独立的端口和 socket跑多个 mysqld 进程。每个实例彼此独立互不干扰。我遇到最典型的场景有两个。一个是混布模式一个实例跑核心业务库另一个实例跑日志库或报表库数据重要性不同但物理资源复用。另一个是环境隔离同一台测试机上开了三套 MySQL分别对应开发、联调、自动化测试端口从 3306 往下错开谁也不会影响谁。这里有个关键点要提前说清楚多实例不等于高可用。如果你想要的是主从复制、故障自动切换那是另一套架构。多实例的核心价值是资源和进程的隔离不是数据的冗余。1.2 多实例、多进程、还是容器在规划方案之前得先知道有哪几条路可以走。纯多实例一个 MySQL 安装目录多个数据目录多个配置文件多个 mysqld 进程。资源利用率相对较好每个实例独立配置 buffer pool、连接数等。多套安装把 MySQL 二进制复制多份每份独立安装目录。适合需要不同 MySQL 版本同时运行的场景。容器化每个容器跑一个实例隔离更彻底但要求团队熟悉容器运维且性能损耗在有状态数据库场景要慎重评估。我个人的建议是版本统一时优先用纯多实例省事、可控、性能损耗小。如果确实需要大版本并存——比如业务 A 只能跑 5.7业务 B 必须上 8.0——那就把安装目录复制成多份方法类似只是路径上多一层区分。纯多实例的隔离粒度是够的。MySQL 的 InnoDB buffer pool、redo log、undo log、binlog 都是实例级的独立资源只要配置文件分开互相就看不到了。唯一共享的只有操作系统资源和二进制安装目录里的共享库文件这在实践中没有影响。1.3 端口的整体规划建议提前把端口规划写进文档别装的时候随手选。常见的 MySQL 端口是 3306从 3307 往后分配。我习惯按业务代号分配比如订单库 3306、用户库 3307、日志库 3308端口号和数据目录名保持一致这样看目录就知道是哪个实例。端口规划的同时要同步规划三个关键文件路径它们是多实例最容易出问题的地方数据目录/data/mysql/3306、/data/mysql/3307socket 文件/tmp/mysql_3306.sock、/tmp/mysql_3307.sockPID 文件/data/mysql/3306/mysql_3306.pid、/data/mysql/3307/mysql_3307.pid这三个路径在所有实例间必须唯一。很多新手第一次装多实例配置文件写得挺好但 socket 和 PID 文件路径漏改两个实例抢同一个文件启动直接失败或者启动成功了但后面怎么都连不上。2. 基础环境准备与目录规划2.1 软硬件要求和版本选择用二进制安装包方式时系统要求不复杂CentOS 7 以上或 Ubuntu 18 以上都行需要 libaio、libnuma 等基础依赖。安装前先确认yum list installed | grep libaio yum list installed | grep numactl缺什么装什么CentOS 下直接yum install -y libaio libaio-devel numactlMySQL 版本这块5.7 和 8.0 的安装目录结构和初始化命令略有差异。8.0 里 mysqld --initialize 是唯一标准初始化方式5.7 也支持但 5.7 早期版本可能还要处理 mysql_install_db 脚本。现在新装环境只要不是业务强依赖旧版本特性我一般建议直接上 8.0。8.0 的默认认证插件 caching_sha2_password 会导致一些老版本客户端连不上这个问题稍后专门讲。2.2 创建用户和目录结构多实例都会用同一个系统用户运行没必要每个实例建一个用户。统一用 mysql 用户groupadd mysql useradd -r -g mysql -s /sbin/nologin mysql mkdir -p /data/mysql/3306 mkdir -p /data/mysql/3307 mkdir -p /data/mysql/3308 chown -R mysql:mysql /data/mysql目录结构上我坚持一个实例一个目录目录下平铺放数据文件、日志、binlog。这样备份和迁移都方便直接把整个目录打包就行。总磁盘容量要提前算好数据目录、binlog、redo log、临时文件都要占空间建议预留至少数据量 1.5 到 2 倍的空余容量避免磁盘写满导致实例直接挂掉。2.3 下载解压安装包下载地址用官网的二进制包就行选择 linux-glibc2.12-x86_64 或对应平台的版本。解压到 /usr/local 下tar -xvf mysql-8.0.36-linux-glibc2.12-x86_64.tar.xz mv mysql-8.0.36-linux-glibc2.12-x86_64 /usr/local/mysql chown -R mysql:mysql /usr/local/mysql这块有个细节值得提一下多实例不要求安装目录里包含数据。mysqld 启动时用 --datadir 指定数据目录所以安装目录是共享的数据目录是独立的。初始化的动作只针对数据目录不会动安装目录。3. 初始化数据目录最容易踩坑的环节3.1 初始化命令的完整写法数据目录初始化是每个实例都要独立执行的。以 3306 实例为例/usr/local/mysql/bin/mysqld \ --defaults-file/etc/my_3306.cnf \ --basedir/usr/local/mysql \ --datadir/data/mysql/3306 \ --initialize先解释一下 --defaults-file 的作用指定这个实例读哪个配置文件。多实例场景下每个实例必须有独立配置文件mysqld 启动时通过 --defaults-file 明确告诉它读哪个而不是默认读 /etc/my.cnf。执行完初始化后注意观察最后几行输出。正常情况会出现类似下面这句[Note] A temporary password is generated for rootlocalhost: 临时密码一串字符8.0 里这个临时密码一定要记下来只显示一次后面找不回来。如果忘了可以停掉实例后用 --skip-grant-tables 跳过权限系统去重置但那是绕路不如初始化时就抄在记事本里。如果不想记临时密码也可以用 --initialize-insecure 参数这样 root 初始密码为空/usr/local/mysql/bin/mysqld \ --defaults-file/etc/my_3306.cnf \ --basedir/usr/local/mysql \ --datadir/data/mysql/3306 \ --initialize-insecure两种方式都可以。我推荐生产环境用 --initialize带随机密码这样首次启动前必须手动找到密码并修改能避免 root 空密码的空窗期。测试环境用 --initialize-insecure 更省事。3.2 初始化失败的排查方向初始化阶段最常见的失败原因我列一下目录权限不对。datadir 不是 mysql 用户所有初始化直接报错。chown 一下就解决了。依赖库缺失。报错信息里会提到缺少 libaio.so.1 之类的库装上就好。配置文件里 datadir 和命令行的 datadir 不一致。mysqld 会检查两个位置不一致时初始化会拒绝执行。二进制文件没执行权限或者架构不匹配。这个比较少见但下载错 tar 包时会出现。初始化完成后数据目录下应该能看到一堆文件包括 ibdata1、ib_logfile0、undo_001、undo_002 等还有 mysql 库的系统表文件。看到这些就说明成功了。3.3 多个实例初始化时要注意的细节如果你要一次初始化 3306、3307 两个实例可以写个简单的循环但循环里有一个坑每条命令必须用不同的 --defaults-file。不然第二个实例初始化时读的还是第一个实例的配置datadir 指向同一个目录直接把第一个实例的数据目录弄乱了或者报错说目录已被初始化。我见过有人在这个环节翻车所以多说一句。初始化完成后不要急着启动先把配置文件里所有参数校对一遍再开始启动。4. 配置文件编写的核心逻辑4.1 一个实例一个配置文件多实例的配置文件我建议放在 /etc 下用 my_端口号.cnf 命名。比如 /etc/my_3306.cnf、/etc/my_3307.cnf。这样好处是systemd 模板里用 %i 传参时可以直接拼接出配置文件名不用每套都手写服务单元。配置文件里必写的几组参数我把它们分成几类。第一类是实例身份类包括 port、server_id、socket、pid-file。server-id 在单机多实例下虽然不直接参与复制但建议还是手动指定且全局唯一稍微有复制需求时不至于重新改配置。[mysqld] usermysql port3306 server_id1 socket/tmp/mysql_3306.sock pid-file/data/mysql/3306/mysql_3306.pid第二类是路径类包括 basedir、datadir、log-error、slow_query_log_file、binlog 相关路径。basedir/usr/local/mysql datadir/data/mysql/3306 log-error/data/mysql/3306/error.log slow_query_log_file/data/mysql/3306/slow.log log-bin/data/mysql/3306/mysql-bin binlog_formatrow第三类是资源类主要是 innodb_buffer_pool_size。多实例场景下这是最关键的参数。8.0 默认 buffer pool 是 128M如果你有 64G 内存跑三个实例但忘了调 buffer pool三个实例共享剩余内存性能发挥不出来。反过来三套业务的 buffer pool 加起来超过物理内存操作系统就会开始 swap数据库响应直接卡死。我有个粗略算法buffer pool 总量控制在物理内存的 50%-60%剩下的留给操作系统缓存、连接线程、排序缓冲等。比如 64G 内存三个实例每个给 10G 到 12G 比较稳。4.2 容易被忽略的配置项多实例下有一些配置容易漏漏了倒不至于启动失败但会在后续使用中给你添乱。explicit_defaults_for_timestamp8.0 默认开启5.7 里要看配置。建议明确写上避免 timestamp 字段的默认值行为在不同实例间不一致。sql_mode多实例要在配置里统一。我遇到过一个项目一个实例的 sql_mode 有 ONLY_FULL_GROUP_BY另一个没有同一个 SQL 在两边结果不一样排查了半天才发现是 sql_mode 的差异。max_connections每个实例单独设。默认 151 太小多实例环境一般建议至少 500具体看业务连接数。character-set-server 和 collation-server建议统一 UTF8MB4这个不用多说。skip-name-resolve这个要看情况。如果业务通过 IP 访问数据库建议开启省去反解析 DNS 的耗时。但如果业务通过域名访问且依赖 host 授权就不要开。4.3 参数校验方法配置写完后启动前用一个命令快速校验/usr/local/mysql/bin/mysqld \ --defaults-file/etc/my_3306.cnf \ --validate-config输出没有报错就说明配置语法和基本依赖没问题。这个命令不会启动实例只做校验多实例配置调整后我都习惯先跑一遍再重启。5. 启动实例与连接验证5.1 手工启动第一个实例初始化完成后手工启动一次确认实例没问题再做 systemd 配置这样排障链路干净。手工启动推荐用 mysqld_safe/usr/local/mysql/bin/mysqld_safe \ --defaults-file/etc/my_3306.cnf mysqld_safe 是一个守护包装器它会监控 mysqld 进程异常退出时会自动拉起。但这也带来一个问题后面配置 systemd 时如果 ExecStart 还走 mysqld_safe会有双重守护的混乱。所以生产上我建议 systemd 直接 ExecStart 指向 mysqld 二进制不用 mysqld_safe。手工启动后先看进程和端口ps -ef | grep mysqld netstat -tlnp | grep 3306看到 mysqld 进程存在、3306 端口监听再去看错误日志 /data/mysql/3306/error.log正常情况下日志末尾会出现 “ready for connections” 的字样表示启动完成。如果日志里有 ERROR 级别的信息先别急着继续把报错处理完再说。5.2 用 socket 和 TCP 分别验证连接$socket 验证mysql -uroot -p -S /tmp/mysql_3306.sockTCP 验证mysql -uroot -p -h 127.0.0.1 -P 3306第一次连接用初始化时生成的临时密码登录后立刻修改密码。8.0 里修改密码的命令ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY NewStrongPass123;注意这里有个坑8.0 默认认证插件是 caching_sha2_password如果业务侧用的是老版本客户端5.x 的驱动或工具连 3306 没问题连 3307 就会报 Authentication plugin caching_sha2_password cannot be loaded 之类的错误。处理办法有两个一是升级客户端驱动二是在创建业务账号时指定 mysql_native_password。为了兼容性测试环境我一般选择二CREATE USER app_user% IDENTIFIED WITH mysql_native_password BY AppPass123; GRANT ALL PRIVILEGES ON app_db.* TO app_user%;生产环境建议用 mysql_native_password 还是升级驱动要根据实际业务栈决定这里不展开说。5.3 第二个实例如法炮制依次把 3307 初始化、启动、连接验证走一遍。不会有什么新问题但要注意 server-id、端口、socket、pid-file 不要和 3306 冲突。建议手工启动两个实例成功后再做开机自启。我提一点手工验证阶段宁可多花十分钟也别急着把 systemd 配好然后重启机器验证。很多人在多实例上栽跟头都是因为系统重启后只有部分实例自动拉起另一个启不来手忙脚乱地排查最后发现在 systemd 里写死了错误路径。6. 开机自启的 systemd 配置6.1 用模板单元管理多实例开机自启这块我强烈推荐用 systemd 的模板服务。模板服务的文件名格式是 name.service启动时通过 systemctl start name实例名 来传参%i 就代表实例名。为 MySQL 多实例创建 /etc/systemd/system/mysqld.service[Unit] DescriptionMySQL Server %i Afternetwork.target [Service] Typesimple Usermysql Groupmysql ExecStart/usr/local/mysql/bin/mysqld --defaults-file/etc/my_%i.cnf ExecReload/bin/kill -HUP $MAINPID TimeoutSec300 Restarton-failure LimitNOFILE65535 [Install] WantedBymulti-user.target这个模板的关键点在于 ExecStart 里 --defaults-file/etc/my_%i.cnf。当执行 systemctl start mysqld3306 时%i 被替换为 3306命令变成/usr/local/mysql/bin/mysqld --defaults-file/etc/my_3306.cnf这样一套模板就能管所有实例新增实例时只需要建配置文件和目录不用再写新的 service 文件。6.2 Typesimple 与 Typeforking 的选择很多老教程里 MySQL 的 systemd 配的是 Typeforking还需指定 PIDFile。这是针对 mysqld_safe 的写法因为 mysqld_safe 会 fork 出 mysqld 子进程父进程退出。但如果 ExecStart 直接跑 mysqld这是模板里的做法mysqld 是前台进程应该用 Typesimple。Typesimple 的话systemd 认为 ExecStart 启动的进程就是主进程它退出就代表服务结束。mysqld 恰好是这种守护进程模式不 fork 到后台直接占用终端。以前我抄过网上一个模板直接用 Typeforking 但 ExecStart 跑的是 mysqld结果 systemctl start 一直等到 TimeoutSec 超时服务状态卡在 activating。后来把 Type 改成 simple问题马上解决。6.3 启动和设置开机自启配置写好后依次执行systemctl daemon-reload systemctl start mysqld3306 systemctl start mysqld3307 systemctl enable mysqld3306 systemctl enable mysqld3307执行 enable 后systemd 会在 /etc/systemd/system/multi-user.target.wants/ 下创建符号链接指向 mysqld.service这就实现了开机自启。验证状态systemctl status mysqld3306 systemctl status mysqld3307这里有几个细节要注意用 systemctl start 后看到状态是 active (running)再去看端口确认一遍有没有真的监听。systemctl 状态和实际进程偶有不同步以端口和进程为准。enable 操作只创建自启链接不会启动服务。很多人以为 enable 后服务马上就在运行了其实不是要先 start 再 enable。systemctl 默认会设置一些资源限制比如文件描述符限制。MySQL 8.0 需要较多文件描述符模板里我用 LimitNOFILE65535 显式放开避免运行中报 Too many open files 错误。6.4 重启验证自启效果配置完成后一定要做一次完整的重启验证。这一步不能省略。reboot机器起来后静默几秒执行systemctl status mysqld3306 systemctl status mysqld3307 ss -tlnp | grep 3306 ss -tlnp | grep 3307两个实例都应该 active (running)。如果某一个没起来看一下对应的 error.log大概率是配置路径或权限问题。7. 常见问题与排查实录7.1 端口和 socket 被占这是多实例最常见的问题。第一个实例起来了第二个实例报 Address already in use或者 MySQL 自己报 Cant start server: Bind on TCP/IP port. Got error: 98.排查方法ss -tlnp | grep 3307如果端口被占看是哪个进程占用的。如果是别的业务程序占用了端口需要协调换端口如果是上一个没退干净的 mysqld 进程占着就 kill 掉它再启动。socket 文件冲突的排查比较隐蔽。如果两个实例配置了相同的 socket 路径第一个实例创建了 socket 文件第二个实例启动时尝试使用同一个文件会报 bind 失败或文件已存在。处理方法让 socket 路径在实例间唯一用 /tmp/mysql_端口号.sock 的格式。启动前如果之前异常退出留下了残留 socket 文件先删掉再启动。7.2 数据目录权限引起的启动失败现象systemctl start mysqld3307 报错日志里提示 Permission denied 或 mysqld: Cant read dir of /data/mysql/3307。原因基本是数据目录的属主不是 mysql。多实例目录是分开创建的有时候忘了 chown 新目录。处理chown -R mysql:mysql /data/mysql/3307这个操作治标治本。顺便检查一下 /usr/local/mysql 的属主之前遇到过安装包解压后用 root 启动过一次之后 mysql 用户权限不够启动也报错。7.3 systemd 单元未找到执行 systemctl start mysqld3306 时如果提示 Unit mysqld3306.service not found常见原因有两个一是服务文件没放到 /etc/systemd/system/ 下或者文件名写错了必须是 mysqld.service 这个格式注意有个 符号。二是在编辑完服务文件后没有 daemon-reload。改过 systemd 配置后一定要 reload第一次创建服务更是如此。7.4 内存溢出和 OOM多实例环境里三个实例的 buffer pool 之和接近物理内存一旦业务并发上来操作系统可能触发 OOM Killer随机杀掉一个 mysqld 进程。排查dmesg | grep -i oom journalctl -k | grep -i oom日志里能看到哪个进程被杀。处理方向有两个。一是把不重要的实例 buffer pool 调小给核心实例让内存。二是对 mysqld 进程设置 oom_score_adj让 OOM Killer 优先杀进程时避开关键实例echo -200 /proc/$(pidof mysqld)/oom_score_adj但通过 systemd 管理时更优雅的方式是在 service 模板里配置 OOMScoreAdjust核心实例的模板单独加或者写在一个带后缀的实例专属 service 覆盖文件里。说实话调低 buffer pool 让它别 OOM 才是正道OOMScoreAdjust 只是最后一道防线靠它保命不太可靠。7.5 老版本客户端认证插件不兼容这个在前面提过。8.0 默认认证插件是 caching_sha2_password如果应用服务器上的 mysql-client 或者 JDBC 驱动版本太老连接时会直接失败。报错信息常见的是Authentication plugin caching_sha2_password reported error: Authentication requires secure connection.处理办法是业务账号创建时指定 mysql_native_password前提是数据库配置文件里没有显式禁用这个插件。如果业务驱动没法升级又对安全性要求没那么高这个方案最省事。7.6 常见问题速查表现象大概率原因处理方式第二个实例启动报端口占用端口冲突或旧进程残留ss 查占用进程kill 残留后启动socket 文件存在但仍启动失败socket 路径冲突或残留文件统一路径格式启动前删除残留文件数据目录 Permission denied目录属主不是 mysqlchown -R mysql:mysql 数据目录systemctl 报 unit 不存在服务文件路径或格式错误检查 mysqld.service 文件名daemon-reloadmysqld 进程被 OOM 杀掉buffer pool 总大小超内存调小次要实例 buffer pool客户端连不上 8.0认证插件不兼容业务账号用 mysql_native_password实例重启后显示启动成功但连接失败端口监听前 TCP 握手有问题日志权限异常查看 error.log 和 socket 文件属主确认 log-error 路径可写实际上多实例的排障逻辑比其他环境简单万变不离其宗先看 error.log再确认端口、socket、PID 文件三件套唯一性最后检查属主和权限。80% 的问题都出在这三个环节里。8. 最后分享一点个人经验多实例安装这件事单看每个步骤都不难难的是每个实例都要做到一模一样不能厚此薄彼。一个实例手工启动成功了另一个实例也要走完整的启动、验证、systemd 配置流程不能图省事只把前面几个实例配了 systemd后面的口头说重启时再手动拉一下。一旦机器重启这样的口头约定就变成事故。我现在的固定做法是目录、配置、systemd 全部在装实例时一次做到位然后所有实例一起 reboot 验证。新增实例时就复制一套对应的目录结构和配置文件把端口和路径改一遍test 环境跑一个冒烟连接就能交付。再补一个小技巧如果服务器上实例很多建议在 /etc/profile.d/ 下写一个环境变量文件把不同实例的 socket 路径预设成 MYSQL_3306_SOCK 之类的变量。平时连接不同实例就不用每次敲一长串路径export MYSQL_3306_SOCK/tmp/mysql_3306.sock export MYSQL_3307_SOCK/tmp/mysql_3307.sock登录后可以直接mysql -uroot -p -S $MYSQL_3307_SOCK这个细节在实例多、切换频繁的时候能省不少事。多实例本身不难难在规范。目录规范、配置规范、systemd 规范这套规范立住了后面扩容多少个实例都只是填表工作。