CentOS 8上使用通用二进制包安装MySQL 8.0.25完整指南
写这篇东西的起因是有个同事照着网上的命令在CentOS 8上装MySQL 8.0.25装到一半就卡住了。先是系统自带MariaDB没清理干净启动时报一长串初始化错误后来又遇到/lib64/libaio.so.1缺失好不容易把依赖补齐又被SELinux拦了权限。他一通折腾之后问我为什么大家都说“一条命令装上”到我这里就成了大型连续翻车现场这个问题其实问到了根子上。CentOS 8上装MySQL社区版用rpm和yum源是最省事的路径但前提是仓库和系统环境都足够干净而“Linux通用二进制包”这种安装方式不依赖系统包管理器本质上是你手动把MySQL完整目录放到指定位置再自己完成初始化、配置、启动整个过程。它看起来麻烦可一旦你把这套路径跑通不管是装8.0.25、8.0.34还是以后要用多实例、多版本隔离思路都是一样的。这篇文章我就拿CentOS 8作为基准系统用通用二进制包的方式装MySQL最新社区版Server 8.0.25把每一步的思路、命令和我在实际部署过程中踩过的坑都写出来给想掌握这套“自己掌握安装主动权”方法的读者一份可以直接照着干的参考。1. 为什么我更推荐用通用二进制包装MySQL而不是yum/rpm1.1 看起来最省事的yum安装其实有不少隐含条件先说说我看到的普遍现象。在CentOS 8上执行dnf install mysql-server系统默认装出来的是MariaDB不是Oracle维护的MySQL社区版。这一点很多新手根本不知道装了之后才发现不对。如果你要装真正的MySQL社区版常见的做法是先下载官方提供的mysql80-community-release-el8的rpm包把官方yum仓库添加进去然后再dnf install mysql-community-server。这条路径本身是可行的但对国内网络环境来说官方仓库下载速度经常不理想如果你的机器在内网环境、没有外网权限yum仓库压根就连接不了。还有更隐性的问题mysql80-community-release这个rpm包本身是随MySQL版本迭代更新的如果你拿的是旧版release包而你的系统Apache或者某些组件正好占用了MySQL相关命名安装时可能会触发依赖校验失败。我自己在某台机器上就遇到过系统里预装了某个依赖库版本号和MySQL官方仓库要求的版本号互相看不顺眼dnf直接报依赖冲突。虽然可以通过--nogpgcheck或者强制安装绕过去但一旦你这么做了后续升级时很容易出现仓库元数据混乱。1.2 通用二进制包的本质手动掌握安装主动权二进制包是什么其实就是官方编译好的mysql-8.0.25-linux-glibc2.12-x86_64.tar.xz这样的压缩包里面装好了MySQL运行所需的所有二进制文件、库文件、头文件和初始配置模板。它不依赖yum、不依赖rpm数据库你只要把文件解压到指定目录手动补上依赖库做好配置和初始化就能运行起来。这样做的好处很直接第一安装路径完全自己控制不用被系统包管理器默认路径绑死第二网络断了、内网离线环境也照样可以装只要把安装包提前拷到服务器上第三同一个系统上可以放多个版本、多套实例互不干扰第四出了问题排查起来更清晰因为所有东西都在你眼皮底下。当然代价也需要直说它比yum装多几步手动操作升级的时候要自己替换二进制包而且要清楚配置文件、数据目录、日志目录的位置。对生产环境来说恰恰这种“可控”比无脑省事更重要。2. 装包之前的系统清理、依赖安装和目录规划2.1 先检查再动手别让旧版本和残留配置阻塞你我见过太多在安装中段翻车的例子翻车原因不是安装步骤本身而是系统早就藏着旧MySQL。所以在下载安装包之前先花两分钟做排查比后期花两小时排错划算得多。# 查看是否已经安装了mysql/mariadb相关软件包 rpm -qa | grep -E mysql|mariadb # 如果存在mariadb相关包建议先移除 dnf remove mariadb* -y # 查看是否残留MySQL的配置文件和数据目录 ls -l /etc/my.cnf /etc/my.cnf.d 2/dev/null ls -l /var/lib/mysql 2/dev/null这里要特别提醒如果之前用rpm方式装过MySQL卸载之后/etc/my.cnf和数据目录大概率还会留在系统里。这些残留不会让你再次安装失败但它会在你启动新MySQL时被当成有效配置加载轻则参数覆盖异常重则数据目录权限错乱。我的习惯是在确认旧数据不需要保留的前提下把/etc/my.cnf、/etc/my.cnf.d、/var/lib/mysql全部备份重命名给新安装一个清爽的起点。2.2 三个必须的依赖库少一个都启动不了MySQL二进制包虽然自带了一堆库文件但有两个系统级共享库它不会自带libaio和libnuma。启动时缺少它们会直接报错弹不出来。# 安装libaio用于异步IO dnf install -y libaio # 安装numactl-libs用于NUMA内存管理 dnf install -y numactl-libs很多教程只提libaio但我实测CentOS 8的系统环境里mysqld启动时同样会去找libnuma.so.1不装照样起不来。另外还需要保证系统里有tar、wget、perl这些基础工具。CentOS 8 minimal安装时通常自带tar和perlwget如果不确定顺手装一下。2.3 专用用户和目录规划先用好名字后面少折腾MySQL官方文档强烈建议不要用root直接跑mysqld要创建一个专用用户。这一步既是为了安全也是为了避免某些初始化逻辑因为权限过大而异常。# 创建mysql用户组和用户禁止登录 groupadd mysql useradd -r -g mysql -s /sbin/nologin mysql然后规划三个核心目录安装目录、数据目录、日志目录。# 安装目录 mkdir -p /usr/local/mysql # 数据目录和日志目录 mkdir -p /data/mysql mkdir -p /var/log/mysql # 赋予mysql用户权限 chown -R mysql:mysql /usr/local/mysql /data/mysql /var/log/mysql数据目录单独放在/data/mysql而不是默认的/var/lib/mysql我觉得在真实部署时很有必要。系统盘和数据盘分开后面磁盘扩容、备份、迁移都方便得多。如果你服务器上已经挂了大容量数据盘直接把数据目录指向那块数据盘对应挂载点即可。3. 核心安装流程下载解压、配置、初始化、启动3.1 下载与解压注意glibc版本和平台架构MySQL 8.0.25的Linux通用二进制包在官方下载页提供。选择时看准文件名里的两个关键信息glibc版本和CPU架构。CentOS 8用的是glibc 2.28所以下载官方标注linux-glibc2.12的包完全没问题这个命名代表最低要求的glibc版本向下兼容。CPU架构选x86_64如果你用的是ARM服务器则要选aarch64对应版本。# 我以8.0.25为例下载好之后解压到/usr/local tar -xvf mysql-8.0.25-linux-glibc2.12-x86_64.tar.xz -C /usr/local # 做一个软链接便于以后升级替换版本 ln -s /usr/local/mysql-8.0.25-linux-glibc2.12-x86_64 /usr/local/mysql这一步我强烈建议用软链接而不是直接把目录改名成mysql。以后升级新版本时把新包解压成新目录确认一切正常后只需把软链接重新指向新目录数据目录和配置文件完全不受影响回滚也只需改软链接。3.2 my.cnf基础配置一份能跑通的参考模板MySQL的配置文件默认会从/etc/my.cnf读取如果存在/etc/my.cnf.d目录它也会加载里面的配置片段。为了便于理解和排查我建议使用一份干净的/etc/my.cnf把核心配置直接写进去。[mysqld] # 基础路径 basedir /usr/local/mysql datadir /data/mysql socket /tmp/mysql.sock pid-file /data/mysql/mysql.pid log-error /var/log/mysql/error.log # 运行用户 user mysql # 端口和监听地址 port 3306 bind-address 0.0.0.0 # 字符集 character-set-server utf8mb4 collation-server utf8mb4_0900_ai_ci # 连接数和基础资源 max_connections 500 default-time-zone 08:00 [client] socket /tmp/mysql.sock default-character-set utf8mb4 [mysql] socket /tmp/mysql.sock default-character-set utf8mb4解释几个容易被忽略的点。basedir是二进制包的根目录datadir是数据目录初始化后生成的系统库表、InnoDB表空间都在这里pid-file是MySQL运行时写的进程ID文件启动脚本判断服务器是否存活靠的就是它log-error是错误日志路径一旦启动失败第一排查点就是它。default-time-zone要按你业务所在时区设置。如果你的业务环境是东八区而服务器系统时区也是东八区这条加不加影响不大但如果服务器时区被设成了UTC而你的业务日志诉求又是本地时间那就必须在配置文件里明确指定否则时间字段会不准。字符集我选了utf8mb4和utf8mb4_0900_ai_ci。MySQL 8.0已经默认utf8mb4但显式写出来的好处是防止初始化时某些系统字段意外落到非utf8mb4同时告知后面接手的同学当时的设计意图。3.3 mysqld --initialize参数顺序这个小细节能省一小时初始化是准备MySQL系统库表、创建root账号的关键命令。MySQL 5.7之后推荐用mysqld --initialize而不是老掉牙的mysql_install_db。这里我要重点讲一个坑它曾经差点把我逼疯mysqld的--defaults-file参数必须放在命令最前面否则会报错。# 正确写法--defaults-file在最前 /usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf --initialize-insecure --usermysql如果你写成# 错误示例启动器会把后面的参数混淆 /usr/local/mysql/bin/mysqld --usermysql --defaults-file/etc/my.cnf --initialize-insecure它极有可能报“unknown variable ‘defaults-file...’”或者干脆忽略配置文件然后初始化到默认路径/var/lib/mysql下。这种问题不细看日志很难察觉等到后面启动时发现数据目录不对才会反应过来初始化就错了地方。关于--initialize和--initialize-insecure的区别简单说前者会在错误日志里生成一个随机临时root密码后者会生成空密码root账号方便你第一次登录之后自己设置密码。我一般在刚上手新环境时用--initialize-insecure少去日志里翻密码这一步登录后再立刻用ALTER USER设置强密码。线上环境如果安全要求严格建议用--initialize把临时密码从日志加密读取。初始化完成后检查一下日志末尾是否有类似“initialization of server has completed”的提示有就说明初始化成功。接着检查数据目录是否生成了文件ls -l /data/mysql正常情况下能看到mysql、performance_schema、sys等目录以及ibdata1、ib_buffer_pool等InnoDB文件。3.4 使用mysqld_safe启动并配置systemd自启初始化完成接下来启动。第一次启动我推荐用mysqld_safe因为它会以后台守护进程方式运行mysqld还能在mysqld意外退出时自动重启方便你先验证基本可用性。/usr/local/mysql/bin/mysqld_safe --defaults-file/etc/my.cnf 启动后等两秒再执行sleep 3 /usr/local/mysql/bin/mysqladmin --socket/tmp/mysql.sock -uroot ping能看到“mysqld is alive”就说明基本起来了。如果ping不通立刻去翻/var/log/mysql/error.log比四处乱猜有用得多。不过mysqld_safe只是临时的启动方式要让MySQL跟随系统开机启动还需要写systemd服务。我在CentOS 8上用的是这样一个unit文件放在/etc/systemd/system/mysql.service[Unit] DescriptionMySQL Community Server 8.0.25 Afternetwork.target Aftersyslog.target [Service] Typeforking Usermysql Groupmysql PIDFile/data/mysql/mysql.pid ExecStart/usr/local/mysql/bin/mysqld_safe --defaults-file/etc/my.cnf ExecStop/usr/local/mysql/bin/mysqladmin --defaults-file/etc/my.cnf shutdown PrivateTmpfalse LimitNOFILE65535 LimitNPROC65535 [Install] WantedBymulti-user.target然后执行systemctl daemon-reload systemctl enable mysql systemctl start mysql systemctl status mysql这里Type选forking因为mysqld_safe会fork一个mysqld主进程后返回。PIDFile路径必须和my.cnf里的pid-file保持一致否则systemd判断服务状态会失准。LimitNOFILE和LimitNPROC是我故意调大的因为MySQL安装目录默认打开文件数限制为1024生产环境下容易报Too many open files提前拉高限制省心。这个文件不是绝对的但对我实际跑的几台机器来说这套配置稳定性和可排查性都很不错。4. 安装完成之后必须做的五件事4.1 设置root密码别用空密码过夜如果你用的是--initialize-insecure现在的root账号是空密码这是绝对不能带线生产的。快速登录并改密码/usr/local/mysql/bin/mysql -uroot -S /tmp/mysql.sock进入mysql命令行后ALTER USER rootlocalhost IDENTIFIED BY YourStrongPss2025; FLUSH PRIVILEGES;如果你用的是--initialize则先查看错误日志中的临时密码grep temporary password /var/log/mysql/error.log然后用临时密码登录再执行上面同样的修改密码语句。要注意8.0默认带validate_password组件密码太简单会直接报错无法执行所以别费劲试“123456”这类的弱密码了。想省事的话后面第6章的修改策略部分有我给的临时策略调整方案。4.2 创建业务账号给最小权限root账号只在本地管理用业务必须建专用账号。创建账号时我强烈建议不要直接给root远程权限也不要给业务账号ALL PRIVILEGES带WITH GRANT OPTION。-- 示例创建一个名为app_user的账号只允许从应用服务器IP段连接 CREATE USER app_user192.168.10.% IDENTIFIED BY AppUserPss2025; -- 只授予业务库的权限而不是所有库 GRANT SELECT, INSERT, UPDATE, DELETE ON biz_db.* TO app_user192.168.10.%;这里无非是遵循最小权限原则。真要整个库误删恢复起来靠备份、靠binlog都很吃力何必给业务账号留这个隐患。如果你有多个应用节点可以按不同网段建不同账号权限完全放开在同一网段其实也还有风险。4.3 确认错误日志和慢查询日志位置生产环境里错误日志哪怕不是一开始就开慢查询至少要把错误日志位置记熟。我前面配置里写的是/var/log/mysql/error.logMySQL会持续把启动错误、运行告警、警告信息写进去。很多启动失败问题的第一现场就在这里。慢查询日志建议在测试环境先开起来。8.0中可以通过SQL临时开启也可以在my.cnf中添加slow_query_log 1 slow_query_log_file /var/log/mysql/slow.log long_query_time 2 log_queries_not_using_indexes 1long_query_time设为2秒的意思是超过2秒的SQL才记录这是比较稳的初始值。如果业务本身对延迟敏感可以再下调到1秒。不过注意慢查询日志本身也会带来一定IO开销线上高峰期别随便重启开启先在低峰期观察一下效果。4.4 配置systemd自启动前面我已经写了unit文件也执行了systemctl enable mysql。这里再强调一个细节如果你后面手动改了unit文件必须重新执行systemctl daemon-reload如果你换了PID文件路径或数据目录也要同步修改unit文件里的配置。很多人明明改了my.cnfsystemd却一直按老配置启动实际上就是漏了daemon-reload。验证自启动是否生效可以重启一次机器或者手动执行systemctl is-enabled mysql输出“enabled”就代表开机启动项已经存在。4.5 防火墙放行或关闭策略确认如果这台服务器有公网IP或者需要跨机器连接必须检查firewalld状态systemctl status firewalld如果防火墙开着放行3306端口firewall-cmd --permanent --add-port3306/tcp firewall-cmd --reload注意这里放行的是所有网卡的3306。更严格的做法是用--add-rich-rule限定来源IP防止数据库端口完全暴露在公网扫描器面前。我自己的习惯是应用服务器和数据库服务器跑在同一个内网段只允许应用网段访问3306其他网段一律拒绝宁可在应用层多做一层转发也不要让数据库裸奔。5. 踩坑实录面对报错日志的完整排查链路5.1 /lib64/libaio.so.1缺失启动器给了最直接的提示我最早一次在CentOS 8上装MySQL时执行mysqld_safe后没看到任何前台输出但ps检查时发现进程根本没起来。去翻错误日志末尾直白地写着error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory这类问题很好排查因为错误信息已经指名道姓。解决办法就是前面第2.2节写的安装libaio和numactl-libs。但我要提醒的是别装完直接又启动同样的报错还会出现在libnuma上干脆一次把两个库都装了。dnf install -y libaio numactl-libs装完之后再启动一般就好了。5.2 SELinux拦截自定义数据目录日志里找得到但不好认CentOS 8默认SELinux是enforcing状态。如果你的数据目录放在自定义路径/data/mysql而你没有给该目录设置正确的SELinux文件上下文MySQL在启动过程中就会因为无法访问数据文件而报错。这类报错在error.log里不会直接写“SELinux deny”而是表现为[ERROR] Cant open the mysql.plugin table. Please run mysql_upgrade to create it. [ERROR] InnoDB: Operating system error number 13 in a file operation.Permission denied的最常见隐藏原因之一就是SELinux。排查命令# 查看mysqld相关的SELinux告警 ausearch -m avc -ts recent如果看到source_context里有mysqld_ttarget_context类型是default_t或者别的非mysqld类型基本可以确定是文件上下文不对。解决办法有两种。第一种是给自定义目录加上和/var/lib/mysql同等的上下文类型dnf install -y policycoreutils-python-utils semanage fcontext -a -t mysqld_db_t /data/mysql(/.*)? restorecon -Rv /data/mysql第二种是暂时把SELinux设为permissive但我强烈不建议一关了之尤其生产环境宁可花五分钟把文件上下文配对也别把系统安全策略整体关掉。配置完之后用ls -Z /data/mysql确认上下文已经变成mysqld_db_t再启动服务就通畅了。5.3 --defaults-file当成率最高的参数顺序坑这个坑我在3.3节提过这里再展开一下因为它真的会让你怀疑人生。某次我在一台机器上初始化MySQL命令写成了/usr/local/mysql/bin/mysqld --usermysql --basedir/usr/local/mysql --datadir/data/mysql --initialize-insecure结果初始化完成后我去/data/mysql里看文件发现还是空的反而/var/lib/mysql下出现了一堆系统库文件。原因就在于没有显式指定--defaults-filemysqld默认把所有官方默认配置加载了一遍datadir回到了默认的/var/lib/mysql。等到我后面用my.cnf里的datadir启动时MySQL发现数据目录为空又临时抛出一堆“Cant open the mysql.plugin table”之类的错误。最终我把初始化命令改成--defaults-file/etc/my.cnf并放在最前面重新初始化才正常。所以这里的通用规则是凡是用mysqld命令带--defaults-file它必须是命令的第一个选项。这算是MySQL一个祖传行为5.7到8.0都这样知道之后可以省下大量试错。5.4 初始化卡住或正常结束但无法启动的杂项问题还有几个频率不算低的小问题我列成清单快速过一下。第一磁盘空间不足。初始化InnoDB会生成好几个文件如果分区只有几个GB空间很容易初始化到一半就异常退出。用df -h检查数据目录所在分区的剩余空间至少留出2GB以上实际生产容量肯定要更大。第二socket文件冲突。如果你在机器上曾经跑过其他MySQL实例/tmp/mysql.sock可能还在。启动新实例前先确认旧实例已完全停止再检查socket文件是否存在必要时手动删除。rm -f /tmp/mysql.sock第三pid文件路径权限不对。my.cnf里配了pid-file/data/mysql/mysql.pid但如果/data/mysql的所有者不是mysqlmysqld就写不进去这个文件。启动时你会看到“Cant start server: Bind on unix socket: Permission denied”或者“The server quit without updating PID file”之类的错误。解决办法还是那句老话chown -R mysql:mysql对应目录。6. 8.0.25版本带来的新习惯和生产环境注意点6.1 caching_sha2_password认证插件老客户端的兼容问题MySQL 8.0开始默认身份认证插件是caching_sha2_password不再是5.7时代的mysql_native_password。这意味着如果你用的是老版本客户端工具比如比较古老的Navicat、某些老JDBC驱动连到这里会直接报“Authentication plugin ‘caching_sha2_password’ cannot be loaded”。排查方法很好判断先用命令行客户端连能连上但程序连不上八成就和认证插件有关。解决办法有两类思路一是修改账号认证插件让老客户端能用ALTER USER app_user192.168.10.% IDENTIFIED WITH mysql_native_password BY 新密码;二是在my.cnf里把默认认证插件全局改回mysql_native_password[mysqld] default_authentication_pluginmysql_native_password不过不到万不得已我不太建议全局改回老插件。因为caching_sha2_password的安全性更高官方也在持续推动生态迁移。如果你只是临时连一下给那个特定账号改掉即可。6.2 validate_password默认策略密码别想着取巧MySQL 8.0的组件机制里validate_password组件默认是启用状态。它默认的密码策略要求密码至少8位包含大小写字母、数字和特殊字符中的至少三类。所以如果你在8.0.25上执行ALTER USER rootlocalhost IDENTIFIED BY 12345678;大概率会收到一条“ERROR 1819 (HY000): Your password does not satisfy the current policy requirements”的报错。这是正常行为不是BUG。如果你是本地测试环境觉得这套策略碍事可以在SQL层临时调整SET GLOBAL validate_password.policy LOW; SET GLOBAL validate_password.length 6;但生产环境我不建议降级。密码策略严格一点至少能在整个体系还没上堡垒机的前提下挡掉一批弱口令问题。真到了需要降级的场景你大概率已经上了更完善的身份认证体系那时候再放开不迟。6.3 默认字符集已经是utf8mb4但要留意排序规则8.0开始默认字符集就是utf8mb4排序规则默认是utf8mb4_0900_ai_ci。新版排序规则对中文、emoji的排序处理比老版本好但我发现不少从5.7迁移过来的团队代码里还写着SET NAMES utf8这在新版下其实也能正常跑可一旦字段里出现4字节字符就可能出现截断或乱码。我的建议是从部署第一天起就把character-set-server和collation-server显式写进my.cnf同时应用层连接参数里明确指定characterEncodingutf8mb4。这样无论以后换机器、换驱动编码行为都是一致的。6.4 生产环境的初始参数别让默认值拖了性能后腿安装完成后用默认参数跑业务不是不行但对正式环境来说至少要把InnoDB缓冲池调出一个合理大小。默认的innodb_buffer_pool_size只有128MB这在一台内存32GB的机器上明显太小业务热点数据放不进内存磁盘IO会被放大好几倍。我常用的一套初始模板[mysqld] innodb_buffer_pool_size 12G innodb_log_file_size 1G innodb_flush_log_at_trx_commit 1 innodb_io_capacity 1000 innodb_io_capacity_max 2000几项配置的含义innodb_buffer_pool_size是InnoDB缓存数据和索引的内存池一般建议设为物理内存的50%到70%之间我这里按一台24G内存的机器为例取12G具体按你的机器调整。innodb_log_file_size是redo log大小8.0默认其实已经从5.7的48MB增大到了100多MB但我还是建议单文件至少1G它能显著降低高并发写入场景下的日志切换频率。innodb_flush_log_at_trx_commit保持默认1保证每次事务提交都刷盘全损风险最低如果对秒级数据丢失不那么敏感可以考虑改成2性能会有一定提升。innodb_io_capacity和innodb_io_capacity_max需要按你磁盘的实际随机读写能力来配。机械盘给几百就行NVMe SSD可以给到2000甚至更高。配置过高不会带来收益配置过低则刷新脏页速度跟不上写入速度可能出现脏页堆积导致的响应变慢。这里提醒一句改生产参数之前务必在测试环境验证一轮尤其innodb_buffer_pool_size这类内存配置配得过大容易造成内存压力和swap反而得不偿失。最后再分享一个小经验。通用二进制包方式装MySQL第一次跑通时感觉步骤很繁琐但跑通之后你会对MySQL的目录结构、配置文件、启动链路理解得更扎实。以后再遇到rpm方式安装产生的问题你能更快判断到底是包管理器的问题、配置的问题还是数据目录的问题。我的实际体会是不要急着追求“一键安装”多花半小时走一遍通用二进制包的完整流程后面省下的排查时间远不止半小时。