☰
MySQL 8 二进制安装实战:从下载解压到 systemd 托管与安全加固
2026/9/26 12:38:09 网站建设 项目流程

mysql8 的二进制安装,是很多生产环境里最常用、也最容易被轻视的一种部署方式。不提 yum 源、不搞源码编译,直接把官方编译好的通用二进制包拉到指定路径,靠 my.cnf 和几条初始化命令把实例拉起来。这种方式在离线内网、统一版本管控、多实例部署这些场景里非常顺手,也是我这些年处理 MySQL 问题时最常复现环境的手段。

这篇文章我会用 CentOS 7 系环境、MySQL 8.0.36 版本为例,把二进制安装的全过程拆开讲清楚,包括下载解压、目录规划、my.cnf 参数、初始化命令、systemd 托管启动、账号安全,还有我踩过的几个坑。Windows 下那种免安装 zip 包其实也属于二进制分发,我会在最后单独说几句。

1. 为什么要用二进制安装,而不是 yum 或者源码编译

1.1 三种安装方式的核心差异

先聊清楚一个很多人搞混的问题:yum 装的 MySQL、源码编译的 MySQL、二进制包安装的 MySQL,到底差在哪?

yum 安装走的是发行版仓库或官方 yum 仓库,好处是依赖自动解决、升级方便,但坏处也很明显——你没得选。仓库里是什么版本就是什么版本,编译参数也是别人定好的。比如某些发行版把INNODB的页面大小、字符集默认值改过,你在生产环境排查问题时,行为跟官方文档对不上,就会很头疼。

源码编译是最灵活的方式,可以精确控制编译选项、裁剪功能模块,但代价是编译时间长(一般要 20 到 40 分钟)、依赖一大堆开发库、出错概率也高。除非你要做二次开发、或者对特定硬件平台做优化,否则在生产环境为了装个数据库去编译源码,性价比很低。

二进制安装正好卡在中间。官方在编译二进制包时,用的是一套经过充分测试的默认配置,你拿到手就能跑,不需要处理编译期的依赖问题,同时版本完全可控、目录完全可控、启动方式完全可控。你要做的只是把文件解压到指定目录,然后自己写配置、自己初始化数据目录。

对于大多数场景,这个方案最合适。多实例部署时尤其明显——你想在一台机器上跑两个 MySQL 8,端口分别是 3306 和 3307,yum 装的那套做起来很别扭,但二进制包想放几个放几个。

1.2 哪些场景必须用二进制安装

我遇到过这么几类场景,二进制安装基本上是唯一解:

第一,内网离线环境。生产区的机器往往不连外网,yum 源是内网镜像,版本滞后且不一定有 mysql8。你拿一个二进制 tar 包拷贝进去,解压就能用,不依赖任何网络操作。

第二,多版本共存。业务还没完成升级,老库跑着 MySQL 5.7,新库要用 8.0,同一台机器上两个版本并存。用 yum 装的话版本冲突问题能把你绕晕,二进制包各放各的目录,互不干扰。

第三,标准化交付。公司内部有统一的 MySQL 部署规范,要求 basedir、datadir、日志路径都是固定位置,配置文件统一模板。二进制包是最容易做出标准化脚本的安装方式。

搞清楚了为什么,下面就直接上手操作。

2. 安装前的环境准备与文件规划

2.1 系统依赖与检查清单

很多人在二进制安装时遇到的第一道坎,是初始化直接报错找不到共享库。MySQL 8 对操作系统的依赖其实很少,但有几个东西必须先确认。

在 CentOS 7 上,先检查这几个依赖包是否已安装:

yum install -y libaio numactl-libs ncurses-compat-libs

libaio必装,MySQL 用异步 IO 就靠它,之前很多人在初始化时报libaio.so.1找不到,就是少了它。numactl-libs和ncurses-compat-libs在某些精简系统上也会缺,顺手装上能省很多事。

接下来检查系统里是否有残留的 MySQL 或 MariaDB:

rpm -qa | grep -i -E 'mysql|mariadb'

如果有,先用rpm -e --nodeps卸载干净。之前见过一台机器上装了 MariaDB 的库文件,结果 MySQL 的 socket 文件和它冲突,初始化成功了却起不来服务,排查半天。

然后检查 3306 端口是否被占用:

ss -lntp | grep 3306

这一步容易忽略,但很重要。很多新手在启动时报Bind on TCP/IP port: Address already in use,原因就是别的进程占着端口。

还有一点很多人没注意:检查/etc/my.cnf是否存在。CentOS 7 的 mariadb-libs 会顺手装一个全局配置文件,如果它存在,后面 MySQL 启动时可能会读到这个残留配置,导致行为异常。建议先看一眼,有内容就先备份再清空,避免干扰。

2.2 下载 MySQL 8 二进制包并校验

下载地址直接去 MySQL 官方下载页的 Community Server 区域,选择 Linux - Generic,这个就是官方通用二进制包。我习惯用国内镜像站下载,比如华为云或者清华的镜像,速度快很多,还支持断点续传。

以 8.0.36 为例,文件名一般是:

mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz

如果你的系统 glibc 版本很低(CentOS 7 是 2.17),选 glibc2.17 这个版本是兼容的。下载后建议做一下 SHA256 校验:

sha256sum mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz

把输出结果跟官方页面上的 checksum 对比,确认包没损坏也没被篡改。这一步在生产环境里是必须的,别省。

2.3 目录规划与用户创建

我个人习惯的目录规划是这样:

BASE_DIR=/usr/local/mysql # 软链指向实际版本目录 DATA_DIR=/data/mysql/data # 数据文件目录 LOG_DIR=/data/mysql/logs # error log、binlog、slow log 都放这里

为什么不直接把解压目录当 basedir?因为后续升级时,只需要把新版本目录解压出来,改一下软链指向,数据目录不动,回滚也方便。这个思路和很多应用的做法一样,把"程序"和"配置数据"分离。

解压并建立软链:

cd /usr/local tar -xvf mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz ln -s /usr/local/mysql-8.0.36-linux-glibc2.17-x86_64 /usr/local/mysql

创建 MySQL 专用系统用户,注意不要用 root 跑 mysqld:

groupadd mysql useradd -r -g mysql -s /sbin/nologin mysql mkdir -p /data/mysql/data /data/mysql/logs chown -R mysql:mysql /data/mysql chown -R mysql:mysql /usr/local/mysql

-r表示创建系统账户,-s /sbin/nologin表示禁止登录,这是安全基线,别图省事给 mysql 用户一个 bash shell。

/usr/local/mysql整个目录 chown 给 mysql 其实有点粗暴,更精细的做法是只把data、logs等需要写权限的目录给 mysql,程序目录保持 root 拥有。但很多生产环境图省事直接整个 chown,目前看问题不大。严谨一点的话,可以这样:chown -R mysql:mysql /data/mysql,程序目录仅保留执行权限,后面运行时只有配置里指定的路径需要写。

3. my.cnf 配置参数的选择与解读

3.1 一份基础可用的 my.cnf

二进制安装最核心的部分就是写配置。MySQL 8 的配置读取优先级是/etc/my.cnf、/etc/mysql/my.cnf、basedir/my.cnf等等,为了让配置明确可控,我会用--defaults-file来指定配置文件,避免系统里残留配置干扰。

下面这份配置,是我多次生产部署验证过的基础模板:

[mysqld] # 基础路径 basedir = /usr/local/mysql datadir = /data/mysql/data socket = /data/mysql/logs/mysql.sock pid-file = /data/mysql/logs/mysql.pid log-error = /data/mysql/logs/error.log # 端口与连接 port = 3306 bind-address = 0.0.0.0 max_connections = 1000 max_connect_errors = 100000 # 字符集 character-set-server = utf8mb4 collation-server = utf8mb4_0900_ai_ci # InnoDB 核心参数 innodb_buffer_pool_size = 2G innodb_log_file_size = 256M innodb_flush_log_at_trx_commit = 2 innodb_flush_method = O_DIRECT innodb_io_capacity = 2000 innodb_io_capacity_max = 4000 # binlog 与事务 server-id = 1 log-bin = /data/mysql/logs/mysql-bin binlog_format = ROW binlog_expire_logs_seconds = 604800 gtid_mode = ON enforce_gtid_consistency = ON # 其他 default_authentication_plugin = mysql_native_password skip-name-resolve = 1 lower_case_table_names = 1

3.2 关键参数的选择理由

这里挑几个容易踩坑的参数详细说说。

character-set-server和collation-server为什么要这么配?MySQL 8 的默认字符集虽然本来就是 utf8mb4,但默认排序规则是utf8mb4_0900_ai_ci,这个排序规则在老客户端和某些同步工具里兼容性不太好。如果你的应用要连接老版本客户端,或者要跟 5.7 做数据迁移,建议显式配成utf8mb4_general_ci。这个决定越早做越好,因为表的排序规则在创建时定下来,后期改非常麻烦。

innodb_flush_log_at_trx_commit = 2是我在生产环境比较常用的值。官方默认值是 1,表示每次事务提交都把 redo log 刷到磁盘,数据最安全,但性能相对低。设为 2 表示每秒刷一次,性能好很多,崩溃时最多丢一秒数据。很多互联网业务能接受这个权衡。但如果是金融类业务,请老老实实用默认值 1。

default_authentication_plugin = mysql_native_password是一个兼容性设置。MySQL 8 默认的认证插件是caching_sha2_password,安全性更高,但有一些老版本客户端(比如 PHP 7.1 之前的 pdo_mysql、某些旧版 Navicat)连不上。如果你确认客户端都支持新插件,这个参数可以不设。设成mysql_native_password会让密码以旧格式存储,安全强度稍弱但兼容性最好。我一般看项目情况,新项目直接用默认,老项目才改。

lower_case_table_names = 1要特别小心。它控制表名大小写是否敏感,在 Linux 上默认是 0(区分大小写),Windows 上默认是 1(不区分)。如果确定未来要把数据从 Windows 迁移到 Linux,或者反过来要在 Windows 上跑同样的库,统一设成 1 能避免一堆"找不到表"的诡异报错。但这个参数必须在初始化数据目录之前就确定,因为初始化之后就不能改了。我遇到过两个系统分别用了 0 和 1,合并数据时表名大小写不一致,简直灾难。

innodb_buffer_pool_size的设置大小,一个通用的参照是物理内存的 60% 到 70%。但要注意,这是在只跑一个 MySQL 实例的前提下。如果同一台机器上还有别的应用,或者跑多个实例,就要分摊。比如一台 16G 内存的机器,只跑 MySQL,设 8G 到 10G 没问题;如果要跑两个实例,各自 4G 到 5G 比较稳妥。设太大反而会因为内存交换影响性能。

4. 初始化数据目录与启动服务的完整实操

4.1 初始化命令与初始密码获取

配置写好了,接下来是初始化数据目录。这一步用mysqld --initialize,注意不是老版本熟知的mysql_install_db,那个在 MySQL 8 里已经废弃了。

/usr/local/mysql/bin/mysqld \ --defaults-file=/etc/my.cnf \ --basedir=/usr/local/mysql \ --datadir=/data/mysql/data \ --initialize --user=mysql

这里有几个细节:

第一,--initialize会生成一个临时 root 密码,打印到 error log 里。初始化完成后立刻去看日志:

grep 'temporary password' /data/mysql/logs/error.log

输出类似这样:

[Note] A temporary password is generated for root@localhost: xxxxxxxx

这个密码拿到手之后复制保存好,一会儿要用的。

第二,初始化时--user=mysql一定要带。不用 root 身份去跑 mysqld,更不能用 root 去初始化数据目录,否则生成的数据文件 owner 是 root,后面启动服务时 mysql 用户没权限读写,直接报错。

第三,--initialize有两种模式。默认模式和--initialize-insecure的区别在于:前者生成随机密码,后者生成空密码。生产环境必须用前者,空密码的 root 账号哪怕只能本机登录,也是安全隐患。

4.2 使用 systemd 托管 MySQL 服务

我不用mysqld_safe直接后台跑,因为 systemd 现在已经是标准,异常退出能自动拉起,开机自启也方便。

在/etc/systemd/system/mysqld.service写入:

[Unit] Description=MySQL Server After=network.target [Service] Type=forking User=mysql Group=mysql PIDFile=/data/mysql/logs/mysql.pid ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf ExecReload=/bin/kill -HUP $MAINPID TimeoutSec=300 PrivateTmp=true [Install] WantedBy=multi-user.target

然后重载服务并启动:

systemctl daemon-reload systemctl start mysqld systemctl enable mysqld

检查启动状态:

systemctl status mysqld -l

如果启动失败,第一件事永远是用cat /data/mysql/logs/error.log看日志。比我见过很多人先去journalctl翻半天,其实 MySQL 自己的 error log 里的报错信息要直观得多。

4.3 登录并完成安全设置

现在用前面拿到的临时密码登录:

/usr/local/mysql/bin/mysql -uroot -p

第一次登录后,MySQL 8 会强制要求先改密码才能执行其他操作,执行:

ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPassw0rd!';

密码复杂度要注意,MySQL 8 的 validate_password 组件默认开启,要求密码至少 8 位,包含大小写字母、数字和特殊字符。你可以设置一个复杂的密码,后续再根据安全策略调整。

改完密码之后,记得刷新权限:

FLUSH PRIVILEGES;

到这一步,一个单机 MySQL 8 实例已经可以正常使用了。本地测试一下:

/usr/local/mysql/bin/mysql -uroot -p -e "SELECT VERSION();"

如果能看到 8.0.36 的版本号,恭喜,安装成功。

5. 远程访问配置与安全加固

5.1 创建远程登录账号

MySQL 安装完成后,默认的 root 用户只能从 localhost 登录,这是安全策略,别去改它。远程访问应该单独建账号:

CREATE USER 'app'@'%' IDENTIFIED BY 'AppPassw0rd!'; GRANT ALL PRIVILEGES ON appdb.* TO 'app'@'%'; FLUSH PRIVILEGES;

'app'@'%'表示这个账号可以从任意 IP 登录。如果业务服务器 IP 固定,强烈建议收紧为类似'app'@'192.168.1.%',只允许内网网段访问,降低暴露风险。

还有一个细节是skip-name-resolve = 1的影响。这个参数启用了之后,MySQL 不会把连接的 IP 反解析成主机名,这意味着授权时不能用'app'@'localhost.localdomain'这种主机名形式,只能用 IP。如果你在配置里加了skip-name-resolve,授权语句里写主机名会匹配不上,报Access denied。要么全用 IP,要么去掉这个参数。

5.2 防火墙与系统的配合

MySQL 装好了,账号也建好了,但远程连不上,十有八九是防火墙没放行。

CentOS 7 用 firewalld:

firewall-cmd --permanent --add-port=3306/tcp firewall-cmd --reload

如果你用的是云服务器,除了系统防火墙,还要检查安全组的入站规则,3306 端口是否放行。

这里多说一句,bind-address 设为0.0.0.0后,MySQL 会监听所有网卡的 3306 端口。如果机器有公网 IP,一定要确认防火墙规则足够严格,只允许业务网段访问,千万别把 3306 直接暴露到公网,不然用不了几个小时就会被扫描爆破。

5.3 日常管理的几个常用检查指令

安装完成后,建议立刻跑一遍下面这几条命令,确认实例状态正常:

# 查看实例运行状态 /usr/local/mysql/bin/mysqladmin -uroot -p status # 查看关键配置是否生效 /usr/local/mysql/bin/mysql -uroot -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';" # 查看监听状态 ss -lntp | grep 3306 # 查看错误日志中是否有异常 tail -f /data/mysql/logs/error.log

把这些记到部署文档里,每次安装完都要执行一遍,形成肌肉记忆。等出问题才去查日志,不如一开始就确认所有参数都符合预期。

6. 常见问题与排查技巧实录

6.1 初始化报错:找不到共享库

这是我见过频率最高的错误。执行mysqld --initialize时报错:

mysqld: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory

这是典型的缺少libaio依赖。解决很简单:

yum install -y libaio

装完再初始化就好了。有时候还会报libnuma.so.1找不到,一样处理,装numactl-libs。

6.2 启动失败:Access denied for user 'mysql'

这个报错通常出现在系统日志里:

[ERROR] [MY-010457] InnoDB: ./ibdata1: 'write' error [ERROR] [MY-011971] InnoDB: Unable to lock ./ibdata1

基本可以判定是数据目录权限问题。确认一下:

ls -ld /data/mysql/data

如果 owner 不是 mysql,执行chown -R mysql:mysql /data/mysql再启动。

这个坑我踩过不止一次,每次都是因为初始化的时候忘了带--user=mysql,导致数据文件 owner 是 root。所以初始化命令里--user=mysql一定不能省。

6.3 远程连接报 1130 错误

错误信息:

ERROR 1130 (HY000): Host '192.168.1.100' is not allowed to connect to this MySQL server

说明 MySQL 拒绝了来自该 IP 的连接。排查步骤:

先确认 MySQL 里的用户表:

SELECT user, host FROM mysql.user WHERE user='app';

看 host 是否是%或者包含你连接源的 IP。不是就重新授权。

再确认防火墙:

firewall-cmd --list-ports

最后确认 bind-address。如果配置里是127.0.0.1,外部 IP 根本到不了 MySQL 这一层,改配置然后重启。

6.4 改了配置参数不生效

很多人改了 my.cnf,重启服务后SHOW VARIABLES查出来还是旧值。原因基本都是参数写错了位置,或者配置文件没被读到。

MySQL 8 的参数分全局、会话两层,部分动态参数可以用SET GLOBAL在线改,但有些参数必须在启动时指定。比如innodb_buffer_pool_size是只读参数,只能通过配置文件修改后重启生效。

另外注意,如果系统里有多个 my.cnf,MySQL 会按优先级读取最后一个。不确定读的是哪个,就用--defaults-file强制指定,一劳永逸。

6.5 忘记密码时的处理办法

这个场景每个 DBA 都遇到过。办法是先用--skip-grant-tables跳过权限表启动:

systemctl stop mysqld /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --skip-grant-tables --skip-networking &

注意--skip-networking很重要,跳过密码验证的同时禁用 TCP 连接,避免被外部访问。

然后登录:

/usr/local/mysql/bin/mysql -uroot

清空密码并恢复正常登录:

FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPassw0rd!';

改完密码后重启服务:

kill $(cat /data/mysql/logs/mysql.pid) systemctl start mysqld

这种方式适合应急,不建议日常使用。

7. 关于 Windows 下免安装版的一些补充

搜索热词里频繁出现 "mysql8 windows安装"、"mysql8免安装版本配置方法",这里也多说几句,因为 Windows 的 zip 包本质上也是一种二进制分发。

Windows 下载页面选 "Windows (x86, 64-bit), ZIP Archive",解压后目录结构和 Linux 版几乎一致,但没有mysql用户的概念,也不需要初始化用户。手动创建一个my.ini,放到解压目录下或者C:\ProgramData\MySQL\,内容类似:

[mysqld] basedir = C:/mysql-8.0.36-winx64 datadir = C:/mysql-8.0.36-winx64/data port = 3306 character-set-server = utf8mb4

注意 Windows 下路径分隔符用正斜杠或者双反斜杠,单反斜杠会被当成转义符。

初始化命令在 Windows 的 cmd 中执行:

mysqld --initialize --console

执行完会在控制台直接打印初始密码。然后注册服务并启动:

mysqld --install MySQL8 net start MySQL8

注意 Windows 版默认lower_case_table_names为 1,表名不区分大小写。如果你在 Windows 上创建的库要迁移到 Linux,表名全是小写那就没问题,但凡混用了大小写,到 Linux 上就会疯狂报错。这是个非常常见的坑,提前知道能避免很多麻烦。

另外 Windows 服务注册之后会以 "MySQL8" 这个服务名出现在服务管理器里,开机自启默认开启,跟 Linux 下 systemd enable 的效果一样。但有两点和 Linux 不同:一是不能通过 systemd 的方式查看日志,要看 error log 文件;二是 Windows 下的--defaults-file路径中包含空格时,需要给整条命令加引号,否则服务启动会失败。用 zip 包在 Windows 上装 MySQL 8 做本地开发环境,整体来说比 Linux 简单不少,但生产环境跑 Windows MySQL 的场景很少,这里不展开。

8. 我的几个实操建议

安装 MySQL 8 本身不是难事,难的是安装完之后的长期维护。有几个细节,是我实际操作中吃过亏之后才形成的习惯。

第一,数据目录和日志目录一定要独立分区。程序文件可以跟系统盘放一起,但数据文件要放在单独的数据盘上。这样系统盘故障重装不影响数据,备份和扩容也方便。如果条件允许,日志文件(binlog、redo log)放在单独的盘上,跟数据文件分开,IO 竞争会小很多。

第二,所有部署操作尽量脚本化。我通常会把安装过程写成一个脚本,传入版本号、端口、数据目录这些变量,几秒钟就能部署一个新实例。脚本化之后,每台机器上的部署动作完全一致,排查问题的时候就少了很多"机器差异"带来的干扰。

第三,升级之前一定全套备份。二进制安装的升级相对简单:解压新版本目录,停掉旧实例,切换软链,启动新实例,然后跑mysql_upgrade(其实 MySQL 8 在启动时会自动检查并升级系统表)。但整个过程有风险,如果数据字典升级失败,回滚就麻烦了。所以在升级前,至少要做一次逻辑备份或者物理备份,别嫌麻烦。

第四,初始化时的 root 临时密码,日志里打印出来之后,建议复制到一个密码管理工具里。我之前有一次初始化完忘记保存,日志又被 logrotate 转走了,只能走--skip-grant-tables那条路重置密码,多花了不少时间。

二进制安装这个技能,看起来就是个基础操作,但实际用好了,能让你在面对各种环境时都游刃有余。上面这些内容和坑,都是我亲手趟过来的,希望能帮你少走点弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询