
最近又有人在群里问CentOS 上装个 MySQL 怎么就这么折腾装完不是连不上就是起不来。细问之下多半是上来就yum install mysql结果系统塞进去的是 MariaDB还有人拿着临时密码登不进去或者配好了远程访问结果 Navicat 疯狂报 SSL 错误。这篇就围绕 LinuxCentOS安装 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 系列的软件包标识是el7CentOS Stream 8 是el8CentOS Stream 9 是el9。MySQL 官方 Yum 源对每个大版本都提供了独立的 rpm 包下载地址里的el7、el8、el9后缀就是给你区分用的下错了版本yum 会直接拒绝安装或者报依赖冲突。再一个关键问题是选 5.7 还是 8.0。CentOS 7 默认的 glibc 是 2.17MySQL 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 包时大概率会撞conflictsystemctl stop mariadb systemctl disable mariadb rpm -e --nodeps mariadb-libs第三件事确认网络和磁盘。在线安装要确保能访问repo.mysql.comcurl -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 用el7Stream 8 用el8Stream 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 rootlocalhost: 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.xzx86 架构还是 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 --usermysql --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 port3306 usermysql最后启动。可以通过 systemd 管理也可以简单点用官方自带的mysqld_safe/usr/local/mysql/bin/mysqld_safe --usermysql 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 rootlocalhost 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.policyLOW;注意SET GLOBAL只对当前实例生效重启后失效。建议把配置写进/etc/my.cnf[mysqld] validate_password.policyLOW个人观点即使是在内网root 密码也别用 123456 这种。MySQL 8.0 的密码策略是保护你的第一道防线真被扫到弱密码丢数据是分分钟的事。4.2 建业务账号和远程连接含防火墙生产环境里不应该用 root 去连库要建独立的业务账号。本着最小权限原则只给够用的权限CREATE USER app192.168.10.% IDENTIFIED BY AppPassword2024!; GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO app192.168.10.%; FLUSH PRIVILEGES;账号里的192.168.10.%意思是只允许这个网段访问。如果你只允许某一台机器就写死具体 IP。如果图省事写成app%等于所有机器都能连内网环境风险还是不小的。MySQL 默认只监听本机回环地址也就是bind-address127.0.0.1想要远程连接必须改配置[mysqld] bind-address0.0.0.0然后重启服务。这一步之后还有一层防火墙CentOS 7 及以上默认跑 firewalldfirewall-cmd --permanent --add-port3306/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_passwordCREATE USER app192.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-serverutf8mb4 collation-serverutf8mb4_0900_ai_ci8.0 的默认排序规则推荐utf8mb4_0900_ai_ci5.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-zone08:00JDBC 连接串里也可以加serverTimezoneAsia/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但目录属主不是 mysqlchown -R mysql:mysql /data/mysql chmod 750 /data/mysql把权限修正后重启systemctl restart mysqld基本能解决。第二个容易被忽略的是 SELinux。CentOS 7 默认开启 SELinuxmysqld 默认只被允许绑定到某些端口和访问某些路径。当你自定义了数据目录或者改了端口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如果没装 semanageyum -y install policycoreutils-python-utils第三个原因可能是my.cnf配置写错。比如pid-file指定的目录不存在或者socket路径写成了无权限的位置。可以用这个命令检查 mysqld 实际会加载哪些配置mysqld --print-defaults5.2 客户端连不上命令找不到、Socket、SSL 报错客户端连接问题更常见。先看命令是否找得着mysql: command not foundrpm 方式安装的 MySQL 客户端通常在/usr/bin/mysqltar.xz 方式的话mysql 二进制在/usr/local/mysql/bin/mysql。后者要加软链ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql或者把路径写进/etc/profile的 PATH。接着看 Socket 报错ERROR 2002 (HY000): Cant 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-modeDISABLEDJDBC 连接串则这样jdbc:mysql://ip:3306/db?useSSLfalseallowPublicKeyRetrievaltrue这里要强调一下生产环境不要直接关 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 PRIVILEGESALTER USER会被拒绝。刷新后重设密码ALTER USER rootlocalhost IDENTIFIED BY NewStrongPassword2024!;改完删掉my.cnf里的skip-grant-tables重启服务恢复正常。这个过程要小心skip-grant-tables模式下所有用户都能免密访问谁都能登进你的库操作完务必立刻移除。排查故障的最后再说一个我自己很受益的习惯。装好 MySQL 后别急着把业务接进来先花十分钟做一件事在my.cnf里把log-bin开起来全量备份脚本顺手配一个 cron。MySQL 的 binlog 平时不显山不露水真遇到误删数据时binlog 回放就是救命稻草。我第一次在生产库上犯误删错误的时候靠的就是 binlog从那以后装任何 MySQL 实例我都默认开 binlog。这个操作成本极低收益却极高强烈建议你下次装完就顺手做了。