说实话,MySQL 8 的安装方式我尝试过不少:容器、源码编译、发行版自带包都碰过,但真要给生产环境做部署,我最后还是会回到“二进制安装”这条路上来。容器适合快速验证,发行版自带包版本滞后,源码编译时间成本和维护成本都不低,唯独官方二进制包,拿来就能跑、环境干净、版本可控,部署完还能顺手拆成多实例。今天把我在 Linux 上用 MySQL 8 二进制包做安装的完整过程、参数选择和踩坑记录整理出来,一次性讲清楚。
这套方法适合谁?适合正在搭测试环境、要给业务库做升级替换、或者想在机器上隔离部署多套 MySQL 的运维和开发同学。跟着下面的步骤走,不需要你怎么懂编译,只要会敲命令、能看懂日志,十分钟左右就能把一套干净的 MySQL 8 跑起来。
1. 为什么我推荐用二进制包安装 MySQL 8
1.1 和源码编译、发行版包、容器方案的区别
先说结论:二进制包是官方编译好的可执行文件集合,你只需要解压、配置、初始化三步。它不像源码编译那样要等 GCC、CMake、Boost 挨个编译,也不像 yum/apt 那样受系统仓库版本节奏限制。
我用 Ubuntu 和 CentOS 都部署过,发行版自带的 mysql-server 经常比官方最新版慢好几个小版本,而且有些衍生系统把 MySQL 拆成了十几个子包,装完还得手动处理依赖。容器方案省事,但如果你要跑多实例、做资源隔离、或者对数据目录有严格权限要求,容器反而增加了一层网络和存储的复杂性。二进制包装在裸机上,把目录规划好,数据文件、日志、配置文件全都可以按你想要的方式摆放,这才是最贴近生产环境的部署姿势。
1.2 二进制安装的适用场景
我自己的实践经验里,下面这几个场景最合适用二进制包:
- 服务器上需要同时保留多个 MySQL 版本做兼容性测试;
- 需要把数据目录放到独立挂在盘上,且不想被系统包管理的行为影响;
- 想要完全控制配置文件的加载路径和参数,而不是被默认配置牵着走;
- 需要离线部署,直接把包拷贝进内网机器就能装。
这套方案也有不适合的场景:比如你只需要一键起一个开发库、对服务器无脑维护要求极高,那 Docker 或系统包可能更省心。但凡是“我要清楚知道这台机器上 MySQL 是怎么跑起来的”这种需求,二进制包几乎是最优解。
2. 安装前的规划与下载选中
2.1 版本和发行版选择
下载之前一定要先确认两件事:支持的 glibc 版本和系统架构。MySQL 官方下载页上 Linux-Generic 包会标明 glibc 版本,比如 mysql-8.0.36-linux-glibc2.17-x86_64,glibc 2.17 对应的是 CentOS 7 这一代系统。如果你的系统更新一些,glibc 版本更高,装低版本 glibc 编译的包通常也能跑;但如果反过来,旧系统装新编译包,就有可能出现 “version `GLIBC_2.28' not found” 这类报错。
查看 glibc 版本用这条命令:
ldd --version架构方面,现在服务器基本都是 x86_64,arm64 的机器要专门选 aarch64 包。下载时别只看版本号,后缀里的 glibc 和架构信息才是决定能不能跑起来的关键。
2.2 目录规划是后面所有操作的基础
二进制安装最值钱的就是目录可规划性。我常用的方案是这样:
| 目录 | 用途 |
|---|---|
| /usr/local/mysql | 程序主目录,解压后的所有二进制和库文件 |
| /data/mysql | 数据目录,实际存放库表文件 |
| /var/log/mysql | 错误日志目录 |
| /var/run/mysqld | pid 文件和 socket 文件目录 |
程序目录放 /usr/local 是约定俗成,符合 FHS 习惯;数据目录单独放,方便未来扩容、迁移或替换磁盘,系统盘损坏了数据还有后路。如果你要跑多实例,每个实例都建一组独立目录,互不干扰。
2.3 下载和基础依赖
到 MySQL 官网的 MySQL Community Server 下载页,选 8.0.x 版本,找 “Linux - Generic” 分类下的 tar.xz 包。命令行下载时可以顺手指定版本号,比如:
wget https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz这里有个容易忽略的点:网络下载完一定要先校验 sha256。官方页面每个安装包旁边都给了 checksum,不校验直接解压,万一包在传输过程中损坏,初始化的时候报错你根本不知道是包坏了还是配置有问题。
二进制包依赖的共享库很少,但 libaio 几乎必装。CentOS 系执行:
yum install -y libaioDebian 系执行:
apt install -y libaio1缺了这个库,mysqld 启动时会报 “error while loading shared libraries: libaio.so.1”,这是最大的新手坑。
3. 核心细节解析与实操要点
3.1 解压后的目录结构,别乱动才是关键
解压命令如下:
tar -xvf mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz -C /usr/local解压出来的目录名带版本号,我一般直接改名为 mysql,方便配置文件和 systemd 服务引用:
mv /usr/local/mysql-8.0.36-linux-glibc2.17-x86_64 /usr/local/mysql解压后你会看到 bin、lib、share、support-files 等目录。bin 下面放着 mysqld、mysql、mysqldump 这些核心工具;support-files 里有 mysql.server 启动脚本;lib 里是运行库。这些目录不需要改动,真正要改的是配置文件、数据目录和日志目录。
有个细节:不要用 root 直接跑 mysqld。二进制包安装时会看到官方文档反复强调要创建 mysql 系统用户,不是形式主义,而是 MySQL 在初始化时会检查目录属主,不按要求做后面权限报错非常多。
3.2 my.cnf 配置文件怎么写,决定了你后面少踩多少坑
MySQL 8 默认会按顺序读取 /etc/my.cnf、/etc/mysql/my.cnf、/usr/local/mysql/my.cnf 等路径。你可以用下面命令确认加载顺序:
/usr/local/mysql/bin/mysqld --verbose --help | grep "Default options" -A 1我习惯把所有自定义配置写进 /etc/my.cnf,一份配置全机器生效,清晰明了。生产环境一份最小但可用的 my.cnf 长这样:
[mysqld] basedir=/usr/local/mysql datadir=/data/mysql socket=/tmp/mysql.sock port=3306 pid-file=/var/run/mysqld/mysqld.pid log-error=/var/log/mysql/error.log character-set-server=utf8mb4 collation-server=utf8mb4_0900_ai_ci default-time-zone='+08:00' max_connections=1000 innodb_buffer_pool_size=1G这里每个参数背后都有实际考量。basedir 和 datadir 必须写,不然 mysqld 会按编译时的默认路径找;socket 放在 /tmp 是大多数客户端工具的默认值,方便连接;utf8mb4 已经是 8.0 的默认字符集,但显式写出来以后别人接手时一眼能看到;innodb_buffer_pool_size 我一般按物理内存的 50%~70% 给,写 1G 只是起步值,后面根据业务再调。
注意,MySQL 8 默认认证插件是 caching_sha2_password,不要再在 my.cnf 里强行指定 mysql_native_password 作为默认插件,新版本里这做法已经不合时宜,还会给后续升级埋坑。旧客户端连不上时,正确的做法是单独给某个账号改用旧插件,后面我会细说。
3.3 初始化数据目录,新旧命令差异别搞混
MySQL 5.7 之前有 mysql_install_db 这个脚本,5.7 之后官方改成了 mysqld --initialize。MySQL 8 已经彻底移除了 mysql_install_db,还在网上搜到旧教程的话直接跳过那段。
初始化有两种模式:
# 模式一:生成临时随机密码,写入错误日志 mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql # 模式二:root 初始密码为空,只建议开发环境用 mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql生产环境永远用第一种模式。第二种模式下 root 密码为空,如果你忘了马上改密码,服务启动后等于裸奔。我吃过这个亏,所以现在就算搭测试环境也是第一个命令,拿到临时密码再改。
初始化时要求数据目录必须为空,如果目录里有残存文件,会直接报错 “The designated data directory /data/mysql is unusable”。所以每次初始化前,我都会先清一次目录:
rm -rf /data/mysql/*4. 我在实操中完整的命令流程
4.1 创建用户、目录并设置权限
下面这段是我实际执行时用的完整命令序列:
# 创建 mysql 系统用户,不能登录 shell useradd -r -s /sbin/nologin mysql # 创建数据目录和日志、运行目录 mkdir -p /data/mysql mkdir -p /var/log/mysql mkdir -p /var/run/mysqld # 把目录属主交给 mysql chown -R mysql:mysql /usr/local/mysql chown -R mysql:mysql /data/mysql chown -R mysql:mysql /var/log/mysql chown -R mysql:mysql /var/run/mysqld有一点特别提醒:chown 别只记得数据目录,/usr/local/mysql 如果属主是 root,mysqld 在运行中需要读写一些临时文件时会报权限错误。程序目录即使不用写,也是 mysql 用户在跑,统一交给 mysql 最省事。
4.2 写配置文件、初始化并登录
把上一节的 my.cnf 内容写入 /etc/my.cnf 后,执行初始化:
/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql初始化过程不一定有输出,正确状态是日志文件生成、数据目录出现一堆文件。接着查临时密码:
grep 'temporary password' /var/log/mysql/error.log日志里会有一行类似于 “A temporary password is generated for root@localhost: xxxx” 的内容。拿到密码后登录:
/usr/local/mysql/bin/mysql -uroot -p登录成功第一件事就是改密码:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrong@Passw0rd';MySQL 8 默认开启密码验证策略,简单密码会被拒绝。如果只是测试环境,可以后续调整 validate_password 的策略参数,生产环境还是老老实实用强密码。
4.3 用 systemd 管理 MySQL 服务
官方 tar 包自带 support-files/mysql.server,但它本质是调用 mysqld_safe 的包装脚本,没有 systemd 那么方便管理和设置开机自启。我更喜欢写一个自己的 systemd unit 文件,放到 /etc/systemd/system/mysqld.service:
[Unit] Description=MySQL Server After=network.target [Service] Type=notify User=mysql Group=mysql PIDFile=/var/run/mysqld/mysqld.pid ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf LimitNOFILE=65536 Restart=on-failure [Install] WantedBy=multi-user.targetType=notify 是这里的关键。MySQL 8 官方二进制包支持 systemd 通知机制,mysqld 启动完成后会主动通知 systemd,这样 systemctl start 命令会等到数据库真正 ready 才返回,比写死 sleep 的脚本优雅得多。接下来:
systemctl daemon-reload systemctl enable mysqld systemctl start mysqld systemctl status mysqld看到 active (running) 就说明服务已经起来了。此时再验证一下端口:
ss -lntp | grep 33064.4 开放远程访问和创建业务账号
本地 root 登录只够管理,业务应用需要单独账号。我习惯按库隔离,比如给 appdb 库建一个只相关权限的账号:
CREATE USER 'app'@'%' IDENTIFIED BY 'App@Passw0rd'; GRANT ALL PRIVILEGES ON appdb.* TO 'app'@'%'; FLUSH PRIVILEGES;这里 % 表示允许任意主机连接。如果只想让某台应用服务器连,把 % 换成具体 IP 更安全。MySQL 8 用户账号的安全程度取决于主机限制、密码策略和权限粒度,不建议一上来就给全局所有权限。
5. 常见问题与排查技巧实录
5.1 初始化报错的典型场景
我统计过自己遇到过的初始化报错,基本集中在三个原因:
| 报错特征 | 原因 | 处理方式 |
|---|---|---|
| datadir is unusable | 数据目录非空或属主不对 | 清空目录,chown -R mysql:mysql |
| libaio.so.1 not found | 缺共享库 | yum install -y libaio |
| unknown variable 参数名 | 配置项写错或版本不支持 | 确认 my.cnf 参数在 8.0 是否有效 |
初始化失败后要看 /var/log/mysql/error.log,不要只看终端那几行。MySQL 的错误日志信息量很大,像 “Permission denied” 后面会明确告诉你哪个文件没权限,顺着路径去查属主基本能解决。
5.2 root 登录不上的几种可能
临时密码登录失败,最常见的原因是你把临时密码里的特殊字符看错了。caching_sha2_password 生成的临时密码里经常有括号、顿号、html 转义字符,复制的时候容易漏后半截。稳妥做法不是复制,而是手动逐字符输入。
另一种情况是初始化用了 --initialize-insecure,root 密码是空,然后你用了mysql -uroot -p回车后不输密码,这当然进不去。空密码登录方式是不带 -p:
/usr/local/mysql/bin/mysql -uroot如果你真的把密码忘了,在本地服务器上临时用 skip-grant-tables 恢复:
# 在 my.cnf 的 [mysqld] 段加一行后重启 skip-grant-tablessystemctl restart mysqld /usr/local/mysql/bin/mysql -urootFLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrong@Passw0rd';改完密码记得把 skip-grant-tables 从 my.cnf 删掉再重启一次。这个参数会让所有认证失效,绝不能长期开着。
5.3 客户端连不上,认证插件惹的祸
这个坑非常经典:MySQL 8.0 默认认证插件是 caching_sha2_password,而很多旧版客户端、老版本的 JDBC 驱动、Navicat 老版本只支持 mysql_native_password。连接时报错一般是 “Authentication plugin 'caching_sha2_password' cannot be loaded”。
解决思路不是改全局默认插件,而是单独给业务账号改认证方式:
ALTER USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'App@Passw0rd'; FLUSH PRIVILEGES;不过 mysql_native_password 在 MySQL 8.0 里已经标记为废弃插件,能不用就不用。新项目建议直接用官方驱动或新版客户端,同时支持 caching_sha2_password,这才是长久方案。
5.4 内存和性能参数,别什么都往 my.cnf 里堆
MySQL 8 默认 my.cnf 不写参数也能跑,但几个关键性能参数必须主动设置。最核心的是 innodb_buffer_pool_size,InnoDB 的缓冲池大小决定了热点数据能缓存多少。物理内存 8G 的机器,我通常设 3G~4G;32G 内存设 20G 左右也不会夸张。计算公式是“物理内存的 50%~70% 减去系统和其他服务余量”。
还有一个变化要提醒:MySQL 8.0.30 开始,redo log 容量参数从 innodb_log_file_size 改成了 innodb_redo_log_capacity,默认配置下它会自动管理。如果你按网上的旧教程在 my.cnf 里同时写两个参数,不仅没意义,某些版本还会造成配置冲突。升级版本后多看看 log,别被旧文档带进坑。
另一个与企业环境强相关的是 max_connections。默认 151 对多连接业务不够,我一般先改成 1000,再用压测工具验证实际负载,而不是盲目往 5000、10000 调,连接数上去了内存占用也跟着上去了。
5.5 端口占用和多实例部署时需要注意什么
第一次启动就失败,多半是端口被占。排查命令:
ss -lntp | grep 3306如果确实有其他实例在跑,要么改端口,要么做多实例部署。二进制安装做多实例非常方便:复制一份配置文件,改 port、socket、datadir、pid-file、log-error,再初始化一个新数据目录,起一个新的 systemd 实例或直接用 mysqld_safe 在指定端口启动。
我实际做过多实例隔离,每个实例一个 /data/mysql_3307、/data/mysql_3308 这样的目录,配置里把端口和 socket 区分开,相互之间完全不影响。这也正是二进制安装相对系统包方案最明显的一个优势:系统包把文件散落在多个路径,多实例配置起来要处理一堆隐藏依赖,二进制包目录即实例,删掉目录即卸载干净。
最后分享一个小技巧:每次改完 my.cnf 重启前,先用命令检查配置是否合法:
/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --validate-config这个命令不会启动服务,只检查配置问题。我自从用了它,因为写错参数导致的服务无法启动问题几乎绝迹。MySQL 8 二进制安装其实没那么玄乎,核心就三步:目录权限正确、配置文件正确、初始化方式正确。把这三个环节把控好,后面所有问题都能在日志里找到答案。