最近又有人在群里问:CentOS 上装个 MySQL 怎么就这么折腾?装完不是连不上,就是起不来。细问之下,多半是上来就yum install mysql,结果系统塞进去的是 MariaDB,还有人拿着临时密码登不进去,或者配好了远程访问结果 Navicat 疯狂报 SSL 错误。这篇就围绕 Linux(CentOS)安装 MySQL 这件事,把版本选择、在线安装、离线安装、初始化和故障排查完整捋一遍,不管你是给虚拟机装环境、给内网服务器部署,还是准备从 CentOS 7 迁到 Stream 系列,应该都能在里面找到能直接抄的步骤。
我这几年前前后后在 CentOS 7.9、CentOS Stream 8、Stream 9 上都装过不同版本的 MySQL,踩过的坑攒了不少。下面不按教科书讲,就按实际动手顺序来,每一步为什么这么做我都会交代清楚。
1. 选对版本再动手:CentOS与MySQL的兼容性判断
1.1 版本配对:CentOS 7/8/9 与 MySQL 5.7/8.0
很多人栽的第一个跟头,是根本没搞清自己的 CentOS 和 MySQL 版本之间的对应关系。CentOS 7 系列的软件包标识是el7,CentOS Stream 8 是el8,CentOS Stream 9 是el9。MySQL 官方 Yum 源对每个大版本都提供了独立的 rpm 包,下载地址里的el7、el8、el9后缀就是给你区分用的,下错了版本,yum 会直接拒绝安装或者报依赖冲突。
再一个关键问题是选 5.7 还是 8.0。CentOS 7 默认的 glibc 是 2.17,MySQL 8.0 官方要求 glibc 2.17 以上,所以可以装。但如果你手头是跑了很多年的老业务,数据库里有大量旧 SQL_MODE 依赖,我建议老老实实用 5.7,兼容性省心得多。新项目直接上 8.0,窗口函数、公用表表达式、默认 utf8mb4 这些能力都是实打实的优势。
MySQL 5.7 官方支持已经在 2023 年 10 月结束,安全更新不再提供。如果你是在新环境里做方案选型,优先考虑 8.0;除非有明确的兼容性约束,否则不要逆着趋势走。
1.2 装机前必须做掉的三件事
安装之前别急着敲命令,花三分钟做掉下面三件事,后面能少折腾一晚上。
第一件事:确认系统版本。用cat /etc/redhat-release看具体版本号,顺便uname -m确认架构是 x86_64 还是 aarch64。别小看这个,我见过有人在 ARM 架构的机器上硬装 x86_64 的 MySQL 包,装到一半报Exec format error,白忙一场。
第二件事:检查系统里有没有自带的 MariaDB。CentOS 官方源里的mysql包实际指向的是 MariaDB,很多教程说yum install mysql就是因为它。先跑一下:
rpm -qa | grep -iE 'mariadb|mysql'如果输出里有mariadb-libs之类的包,最好先卸载掉,不然后续装 MySQL 官方 rpm 包时大概率会撞conflict:
systemctl stop mariadb systemctl disable mariadb rpm -e --nodeps mariadb-libs第三件事:确认网络和磁盘。在线安装要确保能访问repo.mysql.com,curl -I https://repo.mysql.com看一眼通不通。磁盘方面,df -h确认根分区或数据目录所在分区至少留出 5G 以上空间,MySQL 初始化后光系统文件就要几百 MB,数据量大了之后更吃空间。
| 检查项 | 命令 | 目的 |
|---|---|---|
| 系统版本 | cat /etc/redhat-release | 确认 el7/el8/el9,选对源包 |
| 已有数据库 | rpm -qa | grep -iE 'mariadb|mysql' | 避免 rpm 包冲突 |
| 网络连通 | curl -I https://repo.mysql.com | 判断能否用在线源 |
| 磁盘空间 | df -h | 预留足够安装空间 |
2. 在线安装:用官方Yum源一次装好
2.1 配置 MySQL 官方 Yum 源
在线安装最稳健的方式是用 MySQL 官方提供的 Yum Repository,它会把mysql-community-server、mysql-community-client等包的安装源配置好,不需要自己去拼各种依赖。
先下载官方的源 rpm 包并安装。CentOS 7 用el7,Stream 8 用el8,Stream 9 用el9:
# CentOS 7 示例 wget https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm rpm -ivh mysql80-community-release-el7-7.noarch.rpm安装完源之后验证一下:
yum repolist enabled | grep mysql正常情况下能看到mysql80-community这个仓库是 enabled 状态。如果yum repolist输出为空,大概率是 GPG key 导入有问题,可以手动导入:
rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-20222.2 切换 MySQL 版本号
官方源默认启用的是 MySQL 8.0 的仓库,如果你需要装 5.7,得手动切换。用yum-config-manager命令操作:
yum -y install yum-utils yum-config-manager --disable mysql80-community yum-config-manager --enable mysql57-community切完再看一眼仓库状态:
yum repolist enabled | grep mysql确认mysql57-community是 enabled 的再继续。这里有个小坑:CentOS Stream 9 的官方源里已经没有 mysql57-community 了,最小版本只到 8.0,硬要切 5.7 的话 yum 会直接报错说找不到这个仓库。
2.3 安装、启动、拿临时密码
仓库配置好之后,安装就一条命令的事:
yum -y install mysql-community-server安装完成后启动服务,并设置开机自启:
systemctl enable --now mysqldMySQL 首次启动时会自动初始化数据目录,并生成一个临时 root 密码。用下面命令把它捞出来:
grep 'temporary password' /var/log/mysqld.log看到类似这样的输出:
[Note] A temporary password is generated for root@localhost: xxxxxxxx把密码复制保存好,下一步要用。
mysqld首次启动的初始化过程是 8.0 之后引入的机制:数据目录为空时,mysqld 会自动创建系统表并生成随机 root 密码。以前 5.6 时代还得自己跑mysql_install_db,现在已经自动化了。如果你在日志里找不到临时密码,先检查是不是因为数据目录之前已经初始化过,那样不会生成新密码。
3. 离线安装:给内网服务器塞MySQL的两种方案
3.1 方案一:rpm 包离线安装
内网服务器没法访问外网,这是运维里特别常见的场景。离线安装的核心思路是:在一台能联网的机器上下载好所有 rpm 包,然后搬到内网机器上安装。
推荐用yumdownloader或者yum --downloadonly把依赖一并拉下来:
# 联网机器上执行 yum -y install yum-utils mkdir -p /root/mysql-rpm yumdownloader --resolve --destdir=/root/mysql-rpm mysql-community-server--resolve参数会把所有依赖包都下下来,拷到内网机器上后直接:
rpm -ivh /root/mysql-rpm/*.rpm如果缺依赖,rpm 会明确提示缺哪个包。MySQL 8.0 常见的依赖有libaio、numactl-libs、perl、openssl等,这些包在内网机器的系统镜像里基本都能找到,用yum install从本地光盘源或内网镜像源装掉即可。
用 rpm 离线安装时还有一个典型的坑:如果系统里已经装了mariadb-libs,安装mysql-community-libs时会产生file conflict,提示:
file /usr/lib64/libmysqlclient.so.18 conflicts...解决办法是先把 maria 相关的包卸掉再装,但卸之前一定要确认系统里没有别的应用依赖它。
3.2 方案二:tar.xz 通用二进制包
另一种离线方式是用 MySQL 官方提供的通用二进制包,也就是 tar.xz 压缩包。这种方式的最大优势是路径完全可控,适合自定义数据目录、做多实例部署、或者不想被 rpm 管理策略限制的场景。
去 MySQL 官网下载mysql-8.0.xx-linux-glibc2.17-x86_64.tar.xz(x86 架构还是 aarch64 别选错),然后执行:
tar -xf mysql-8.0.xx-linux-glibc2.17-x86_64.tar.xz -C /usr/local/ mv /usr/local/mysql-8.0.xx /usr/local/mysql接着创建 mysql 用户、准备数据目录:
useradd -r -s /sbin/nologin mysql mkdir -p /data/mysql chown -R mysql:mysql /data/mysql初始化数据目录,注意--initialize-insecure表示生成空密码的 root 账号,内网环境方便调试;如果需要和 rpm 一样的随机密码机制,用--initialize:
/usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql然后手写一份/etc/my.cnf:
[mysqld] basedir=/usr/local/mysql datadir=/data/mysql socket=/tmp/mysql.sock pid-file=/var/run/mysqld/mysqld.pid port=3306 user=mysql最后启动。可以通过 systemd 管理,也可以简单点用官方自带的mysqld_safe:
/usr/local/mysql/bin/mysqld_safe --user=mysql &3.3 两种方案怎么选
| 对比项 | rpm 包离线 | tar.xz 二进制 |
|---|---|---|
| 依赖处理 | rpm 自动处理,冲突更少 | 完全手动,路径自己控 |
| 数据目录 | 默认/var/lib/mysql | 自定义路径灵活 |
| 升级方式 | yum update直接升级 | 换软链重启,回退也容易 |
| systemd 集成 | 安装即自带服务 | 要手写 service 文件 |
| 多实例部署 | 较麻烦 | 很方便 |
我的建议:没人维护的测试环境用 rpm,省事;生产环境如果对路径、目录规划有要求,或者打算一个机器跑多个 MySQL 实例,用 tar.xz 通用二进制包更合适。rpm 装完后照样能改datadir,但改完要处理 SELinux 标签,反而多出不少事。
4. 初始化与安全加固:拿到临时密码后的正规操作
4.1 修改 root 密码,顺便处理密码强度策略
拿到临时密码后,第一件事就是登进去改密码。
mysql -uroot -p然后执行:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPassword2024!';如果新密码太简单,MySQL 8.0 默认开启的validate_password插件会直接拒绝。想调整策略的话:
SHOW VARIABLES LIKE 'validate_password%';常见的变量是这么几个:
validate_password.policy -> MEDIUM validate_password.length -> 8测试环境想放宽一点,把 policy 改为 LOW 即可:
SET GLOBAL validate_password.policy=LOW;注意SET GLOBAL只对当前实例生效,重启后失效。建议把配置写进/etc/my.cnf:
[mysqld] validate_password.policy=LOW个人观点:即使是在内网,root 密码也别用 123456 这种。MySQL 8.0 的密码策略是保护你的第一道防线,真被扫到弱密码,丢数据是分分钟的事。
4.2 建业务账号和远程连接(含防火墙)
生产环境里不应该用 root 去连库,要建独立的业务账号。本着最小权限原则,只给够用的权限:
CREATE USER 'app'@'192.168.10.%' IDENTIFIED BY 'AppPassword2024!'; GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app'@'192.168.10.%'; FLUSH PRIVILEGES;账号里的192.168.10.%意思是只允许这个网段访问。如果你只允许某一台机器,就写死具体 IP。如果图省事写成'app'@'%',等于所有机器都能连,内网环境风险还是不小的。
MySQL 默认只监听本机回环地址,也就是bind-address=127.0.0.1,想要远程连接必须改配置:
[mysqld] bind-address=0.0.0.0然后重启服务。这一步之后还有一层防火墙,CentOS 7 及以上默认跑 firewalld:
firewall-cmd --permanent --add-port=3306/tcp firewall-cmd --reload最后测试远程连接,客户端命令行或 Navicat 都行。如果你数据库前面挂了连接池(比如 HikariCP 或者 Druid),记得检查连接池的wait_timeout和max_connections两个参数,连接池空闲连接被服务端回收后,客户端会报Connection has been closed。
还有一个兼容性问题值得单独说:MySQL 8.0 默认的认证插件是caching_sha2_password,老版本的 Navicat 或旧版 JDBC 驱动会报错:
Authentication plugin 'caching_sha2_password' cannot be loaded两个解决办法:升级客户端驱动是首选;如果客户端暂时升不了,可以把账号的认证插件改为老的mysql_native_password:
CREATE USER 'app'@'192.168.10.%' IDENTIFIED WITH mysql_native_password BY 'AppPassword2024!';但这只是过渡方案,新代码尽量切新驱动。
4.3 字符集、时区,以及一个默认值0的小坑
装完 MySQL 后建议立刻检查字符集配置:
SHOW VARIABLES LIKE 'character_set%';如果character_set_server不是utf8mb4,赶紧改。utf8mb4 和 utf8 的区别在于:utf8 在 MySQL 里最多 3 字节,存不了 emoji 和部分生僻字;utf8mb4 是完整的 4 字节 Unicode。哪怕业务现在用不到,先配上不会有坏处。
修改/etc/my.cnf:
[mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_0900_ai_ci8.0 的默认排序规则推荐utf8mb4_0900_ai_ci,5.7 没有这个规则,用utf8mb4_general_ci即可。
注意:如果一个库已经建好了,只改全局字符集不会影响已有的表和字段。需要手动转换:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
时区也是一个常见坑。国内服务器默认时区是 CST,但 MySQL 系统默认是 UTC,业务日志、统计报表时间很容易差 8 小时。在my.cnf里加上:
[mysqld] default-time-zone='+08:00'JDBC 连接串里也可以加serverTimezone=Asia/Shanghai双保险。
有一个和“默认值”相关的细节我也一并说了。MySQL 建表时如果想让某个字段默认填 0,写DEFAULT 0就行。但注意:日期时间类型不能随便设默认值,8.0 里datetime DEFAULT CURRENT_TIMESTAMP这个用法很常见,但如果你想设datetime DEFAULT '0000-00-00 00:00:00',默认会失败并报Invalid default value,需要在sql_mode里临时去掉NO_ZERO_DATE才能允许。这种需求实际很少,不要为了图省事牺牲完整性约束。
5. 安装故障排查:几个经典坑的完整链路
5.1 服务器起不来:日志、权限、SELinux 一条线
如果你执行systemctl start mysqld后服务一直起不来,先别急着重启,按链路排查。
第一步,看日志:
journalctl -u mysqld -n 50 tail -n 30 /var/log/mysqld.log/var/log/mysqld.log是 MySQL 自己的错误日志,绝大多数启动失败的根因都在这里。日志末尾会有[ERROR]开头的记录,直接定位问题。
最常见的失败原因是数据目录权限不对。比如你手动改了datadir=/data/mysql,但目录属主不是 mysql:
chown -R mysql:mysql /data/mysql chmod 750 /data/mysql把权限修正后重启systemctl restart mysqld基本能解决。
第二个容易被忽略的是 SELinux。CentOS 7 默认开启 SELinux,mysqld 默认只被允许绑定到某些端口和访问某些路径。当你自定义了数据目录,或者改了端口,SELinux 会拦着不让启动。
查看状态:
sestatus临时关闭验证一下:
setenforce 0如果临时关闭后 mysqld 能正常启动,说明确确实实是 SELinux 在作祟。生产环境不建议永久关闭 SELinux,更规范的做法是把规则加进去:
semanage port -a -t mysqld_port_t -p tcp 3306 semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?" restorecon -Rv /data/mysql如果没装 semanage:
yum -y install policycoreutils-python-utils第三个原因可能是my.cnf配置写错。比如pid-file指定的目录不存在,或者socket路径写成了无权限的位置。可以用这个命令检查 mysqld 实际会加载哪些配置:
mysqld --print-defaults5.2 客户端连不上:命令找不到、Socket、SSL 报错
客户端连接问题更常见。先看命令是否找得着:
mysql: command not foundrpm 方式安装的 MySQL 客户端通常在/usr/bin/mysql;tar.xz 方式的话,mysql 二进制在/usr/local/mysql/bin/mysql。后者要加软链:
ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql或者把路径写进/etc/profile的 PATH。
接着看 Socket 报错:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket'/tmp/mysql.sock'出现这个,要么是服务没起来,要么是 socket 路径和你客户端配置的不一致。检查/etc/my.cnf里[mysqld]和[client]段的 socket 路径是否一致,不一致就改成同一个。
还有一个高频报错是 SSL 相关的:
ERROR 2026 (HY000): SSL connection error: SSL_CTX_set_default_verify_paths failed或者 JDBC 连接时:
SSL connection error: unknown protocol原因是 MySQL 5.7 之后默认启用 SSL,但内网环境很少有正规证书,客户端在验证自签名证书时失败。测试环境临时绕过的方法:
mysql -uroot -p --ssl-mode=DISABLEDJDBC 连接串则这样:
jdbc:mysql://ip:3306/db?useSSL=false&allowPublicKeyRetrieval=true这里要强调一下:生产环境不要直接关 SSL。内网低信任域,或者涉及敏感数据的场景,建议配置正式证书而不是图省事关闭加密。自签名的证书只要客户端和服务端都认,也能保障链路加密。
还有一类 Navicat 报错是前文提到的认证插件问题,报 1251 错误码。老版本 Navicat 认mysql_native_password,不认 8.0 默认的caching_sha2_password,处理方式上面写过了,升级客户端或改认证插件二选一。
5.3 忘记 root 密码的救援操作
运维的人一定会碰上这种情况:root 密码忘了,或者同事把 root 密码改没记。MySQL 提供了一个维护模式入口。
在/etc/my.cnf的[mysqld]段加一行:
[mysqld] skip-grant-tables重启服务:
systemctl restart mysqld这时候不需要密码就能登进去:
mysql -uroot进入后先刷新权限:
FLUSH PRIVILEGES;注意 8.0 在 skip-grant-tables 模式下,如果不先FLUSH PRIVILEGES,ALTER USER会被拒绝。刷新后重设密码:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPassword2024!';改完删掉my.cnf里的skip-grant-tables,重启服务恢复正常。这个过程要小心:skip-grant-tables模式下,所有用户都能免密访问,谁都能登进你的库,操作完务必立刻移除。
排查故障的最后再说一个我自己很受益的习惯。装好 MySQL 后,别急着把业务接进来,先花十分钟做一件事:在my.cnf里把log-bin开起来,全量备份脚本顺手配一个 cron。MySQL 的 binlog 平时不显山不露水,真遇到误删数据时,binlog 回放就是救命稻草。我第一次在生产库上犯误删错误的时候,靠的就是 binlog,从那以后装任何 MySQL 实例我都默认开 binlog。这个操作成本极低,收益却极高,强烈建议你下次装完就顺手做了。