
CentOS上装MySQL这活儿我少说干了七八年但每次碰到新环境还是会心里默念一句“别出幺蛾子”。因为这件事真正的坑从来不在“安装”本身而在于你用的是哪种安装方式、装的是哪个版本、底下的Linux环境到底干不干净。很多人第一次在CentOS上装MySQL网上搜了一堆教程照着敲完命令结果不是启动失败就是连不上数据库回头一看问题全出在最基础的选择上。所以这篇把CentOS装MySQL的完整思路拆开讲清楚覆盖yum安装、tar包手动安装、初始化配置、安全加固和日常排障。不管你是刚接触Linux的运维新人还是想在生产环境里落地MySQL的老手都可以当成一份实操手册来用。前面几节讲清楚“为什么要这么做”后面几节全是能直接抄作业的命令和配置。1. 安装之前先搞清楚的几个底层问题很多人盲目执行命令根本不看自己机器上的环境装完就报错。在动手之前有几件事必须先想明白否则你后面会花更多时间填坑。1.1 选5.7还是8.0不能只看“新版更好用”你打开MySQL官网会发现最新GA版本是8.0系列但在CentOS这种环境里5.7依然是大量生产环境的默认选择这里有几个非常现实的原因。第一5.7是最后一个能用原生my.cnf一套参数直接跑起来的常用版本8.0的默认参数和认证插件变化非常大。第二很多老业务系统的代码是拿mysql-connector-java 5.x写的连8.0会报SSL和认证方式不兼容的问题。第三8.0在部分低配置机器上内存占用明显更高innodb_buffer_pool等参数默认值的计算逻辑也更激进。如果你用的是1C2G的小机器装完8.0可能还没导入数据内存就报警了。如果你只是想学习或者有新项目从零开始8.0其实没问题。但如果你是在维护老业务、或者是从5.6/5.7迁移过来我建议老老实实选5.7。这也是为什么下面讲yum安装时会专门把5.7和8.0的安装方式都讲一遍而不是只给一个默认装最新版的命令。1.2 CentOS自带的“MySQL”根本不是MySQLCentOS 7系列默认软件源里带的是MariaDB很多人刚执行完yum install mysql会发现自己装了一个MariaDB,内心无比困惑。MariaDB是MySQL的一个分支CentOS里默认源带的是MariaDB 5.5版本年代非常久远跟MySQL官方版的语法和行为都有差异。更关键的是如果你想用yum方式装官方MySQL第一步往往是先把系统自带的MariaDB相关包卸载掉否则两个数据库的文件会冲突尤其是/var/lib/mysql目录和数据文件如果已经被MariaDB初始化过后面装官方MySQL的时候很容易报“datadir already exists”之类的错误。所以在装之前先检查一遍系统里有没有残留的数据库安装用下面几条命令rpm -qa | grep -i mysql rpm -qa | grep -i mariadb如果发现有mariadb-libs或者mariadb-server之类的包在可以接受的范围内直接卸载掉。不过要留意mariadb-libs可能会和一些系统组件存在依赖关系卸载前可以用yum remove --assumeno先做个预估。最省心的做法是先保留也行只要你在后文初始化MySQL时指定了独立的datadir和端口和MariaDB装在一起也能跑但如果你没有特殊需求别留着给自己添堵。1.3 安装方式对比yum、tar包、源码编译、Docker在主流的安装方式里我对它们的建议排序是这样的安装方式优点缺点适用场景yum/RPM安装快依赖自动处理省心版本不能随意选可能存在官方源和系统源冲突绝大多数场景的首选tar二进制包版本自由指定路径非常灵活和系统解耦干净依赖需要自己补齐初始化和启动脚本要手工处理离线环境、生产环境多实例、需要锁版本源码编译参数完全可控编译时间极长依赖极多维护成本高极少除非你要改内核特性Docker隔离好部署干净数据持久化和权限管理是坑容器升级/迁移套路不同本地开发、CI环境、微服务架构下面正文就以yum和tar包两种方式做详细展开。因为这两条路线基本上覆盖了我实际工作里95%以上的场景。至于Docker方式我在文末单独讲一段关于它和原生部署的取舍。2. yum安装MySQL全流程5.7和8.0都能用yum安装是最省事的一条路但前提是你配置的yum源必须正确。很多教程让你直接yum install mysql结果装出来是MariaDB或者源里根本没有mysql-server包原因就是没有先把官方源加进去。2.1 清理环境卸载残留数据库这一步做完开始正式配置。先用命令确认一下安装包的来源yum list | grep mysql如果你看到的是mysql-community-server或者mysql-server这样的包名说明你的源里已经具备安装条件。如果什么都不显示或者只有mariadb的相关包那就需要手动添加MySQL官方yum源。添加官方yum源的方式很简单官方给了一个专门的RPM包。在CentOS 7上执行下面的命令yum localinstall -y https://repo.mysql.com/mysql57-community-release-el7-11.noarch.rpm这个RPM不会直接装上MySQL只是把MySQL官方的yum仓库信息写入系统同时默认启用5.7的源禁用8.0的源。如果你想装8.0命令要换成mysql80-community-release-el7-7.noarch.rpm装好之后用下面命令查看当前启用的源yum repolist all | grep mysql看到mysql57-community标记为enabledmysql80-community标记为disabled说明status是OK的。以5.7的repo包为例如果你后续想切换到8.0可以用以下命令手动调整yum-config-manager --disable mysql57-community yum-config-manager --enable mysql80-community2.2 执行安装和首次启动环境清理完源也配置好后安装就非常简单了yum -y install mysql-community-server这个命令会自动解析依赖安装mysql-community-client、mysql-community-common、mysql-community-libs等一系列包。这里要注意的一点是MySQL 5.7安装完成后数据目录默认在/var/lib/mysql配置文件在/etc/my.cnf日志文件在/var/log/mysqld.log这些路径都属于默认路径。如果你后面改配置要改的就是/etc/my.cnf。安装完成后启动服务systemctl start mysqld systemctl enable mysqld启动后立刻检查状态systemctl status mysqld看到active (running)说明启动成功。如果没有启动成功先看日志tail -n 50 /var/log/mysqld.log注意5.7版本在第一次启动时会自动执行数据目录初始化并生成一个临时root密码。这个密码会写在mysqld.log里用下面命令过滤出来grep temporary password /var/log/mysqld.log输出会像这样2023-08-12T03:15:20.123456Z 1 [Note] A temporary password is generated for rootlocalhost: xxxxxx冒号后面那串就是临时密码。2.3 首次登录、改密码和基础验证拿着临时密码登录root命令是mysql -uroot -p输入临时密码之后会直接进入MySQL命令行。但此刻你什么都做不了因为MySQL强制要求先修改root密码执行ALTER USER rootlocalhost IDENTIFIED BY YourNewPassword; FLUSH PRIVILEGES;密码复杂度是MySQL 5.7引入的validate_password插件在起作用。如果你的新密码太简单比如全是数字或纯字母会报“Your password does not satisfy the current policy requirements”。这个插件后面会讲怎么调如果你是在测试环境想用简单密码可以先关掉策略再设置。临时密码阶段千万别想着跳过改密码环节否则很多操作都会被拒绝。改完密码后用新密码重新登录一次试试再用下面几条命令做个基础验证SELECT VERSION(); SHOW DATABASES;能返回版本号和默认的几个库information_schema、mysql、performance_schema、sys说明yum安装这条路已经走通了。3. tar包手动安装自由度和可控制性最高虽然yum安装很快但到了生产环境或特殊网络环境yum装法常常会翻车。比如机器没法访问外网比如你需要装一个特定小版本避免和业务代码不兼容比如你需要在同一台机器上跑多个MySQL实例。这些时候tar包手动安装就是最靠谱的方案。3.1 明确子场景什么时候必须用tar包我经历过的最典型场景是客户内网环境完全隔离所有软件包都需要离线导入。这时候yum源形同虚设Docker更是没得玩必须用二进制tar包直接落地。还有一个场景是版本匹配。你用的ORM框架或者老版连接驱动只支持到MySQL 5.7.30左右但yum源里5.7系列已经更新到5.7.44虽然是同大版本但如果你不想承担任何小版本升级带来的隐性风险直接下载对应版本的tar包是最稳的。另外服务器上同时跑多个MySQL实例时tar包安装的优势就非常明显了。你可以把实例A放在/app/mysql3306实例B放在/app/mysql3307各自的my.cnf独立、数据目录独立、socket文件独立互不干扰。这种多实例部署在yum安装方式下要绕很多弯。3.2 下载与解压准备MySQL官方提供两种二进制包glibc版本和musl版本绝大多数CentOS环境用glibc版本就行。以5.7.44为例下载地址形如wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz如果你在下载站上找不到对应版本可以到镜像站找比如国内一些高校镜像站或者云厂商的开源镜像都会同步MySQL的二进制包。下载前注意核对架构x86_64还是aarch64犯这个错的人不少。确认无误后解压tar -xzf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz mkdir -p /usr/local/mysql mv mysql-5.7.44-linux-glibc2.12-x86_64/* /usr/local/mysql/建议用mv把整个目录内容移动到统一路径这样后续环境变量、服务脚本、配置路径都一致。再创建软链接也是常见做法但我更推荐直接固定目录避免生产环境上软链多跳一层出问题。接着创建MySQL系统用户注意这个用户不需要登录shell仅用于运行mysqld进程groupadd mysql useradd -r -g mysql -s /bin/false mysql chown -R mysql:mysql /usr/local/mysql这里有个依赖需要提前装好MySQL二进制包运行时依赖libaio和numactl库不带这两个库直接跑mysqld启动阶段会直接报错。CentOS上执行yum -y install libaio numactl-libs3.3 编写my.cnf并初始化数据目录tar包的配置文件yum装在/etc/my.cnf不同yum安装会有一个默认配置tar包则完全没有配置。你需要手动创建配置文件。一个最小的、可用的my.cnf至少包含下面这些行[mysqld] basedir/usr/local/mysql datadir/data/mysql/data socket/tmp/mysql.sock port3306 usermysql log-error/data/mysql/logs/mysqld.log pid-file/data/mysql/run/mysqld.pid character-set-serverutf8mb4 collation-serverutf8mb4_general_ci先别急着加各种调优参数目标是把这个文件写得足够简单、能跑起来。再强调一遍datadir如果是自定义的需要先手动创建目录并调整属主mkdir -p /data/mysql/data /data/mysql/logs /data/mysql/run chown -R mysql:mysql /data/mysql然后执行初始化。5.7之后的初始化命令是mysqld --initialize这个命令会生成临时root密码如果你想先获得一个空密码的root更方便自动化初始化可以用mysqld --initialize-insecure。具体看你哪个更顺手cd /usr/local/mysql bin/mysqld --defaults-file/etc/my.cnf --initialize注意如果用了--initialize会像yum安装一样把临时密码输出到log-error指定的日志文件里。如果用了--initialize-insecure则root初始密码为空登录后必须立刻改密码。初始化完成后可以用mysqld_safe启动也可以把mysql.server脚本放到/etc/init.d下直接service方式管理。mysql.server这个脚本在安装包的support-files目录里复制过去修改一下即可cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql.server chmod x /etc/init.d/mysql.server /etc/init.d/mysql.server start但我个人更推荐用systemd管理新建一个mysql.service单元文件指定好ExecStart参数这样后续的开机自启、故障自动拉起、日志管理都会更顺手。这个做法需要额外写一点配置好处是长期收益大特别是生产环境上。对于第一次做的同学先不用太纠结跑通mysqld_safe代码优先。3.4 如果想把tar包方式融入systemd写一个systemd服务文件文件路径为/usr/lib/systemd/system/mysqld.service内容大致如下[Unit] DescriptionMySQL Server Afternetwork.target [Service] Usermysql Groupmysql Typeforking PIDFile/data/mysql/run/mysqld.pid ExecStart/usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf --daemonize --pid-file/data/mysql/run/mysqld.pid ExecReload/bin/kill -s HUP $MAINPID ExecStop/bin/kill -s TERM $MAINPID Restarton-failure RestartSec5s LimitNOFILE65535 [Install] WantedBymulti-user.target记得先把mysqld.pid文件路径和my.cnf里的pid-file配置对齐否则systemd管理时会因为找不到pid文件而判断启动失败。配置好以后通过以下命令管理systemctl daemon-reload systemctl start mysqld systemctl enable mysqld这样从tar包手动安装就升级成了systemd管理的正式服务后续重启机器、日志查看、异常拉起都有了保障。4. 初始化配置、安全加固与生产参数调整安装只是第一步装完一台裸的MySQL相当于买了一台没有上锁的仓库数据放里面极度不安全。下面这些配置和操作不管你是yum装的还是tar包装的都建议按顺序做一遍。4.1 安全初始化脚本可以跑但不能盲跑MySQL安装包里自带了一个安全脚本叫mysql_secure_installation。它会引导你完成几件事设置root密码、删除匿名账号、禁止root远程登录、删除test数据库。这个脚本本身很好用我不会劝你不要用但它推荐的策略不一定适合你的场景。比如它默认会禁止root远程登录但在内网环境里很多运维习惯直接拿root远程连库做临时排查这个被禁掉之后反而要再多加一步白名单账号。我自己跑这个脚本的习惯是执行之前先手动在MySQL里创建一个专用管理账号比如adminlocalhost并授予全部权限作为备用然后再跑安全脚本这样即使root权限被收窄也不会把自己锁在门外。CREATE USER adminlocalhost IDENTIFIED BY YourStrongPassword; GRANT ALL PRIVILEGES ON *.* TO adminlocalhost WITH GRANT OPTION; FLUSH PRIVILEGES;4.2 密码策略插件该关就关该调就调MySQL 5.7和8.0在初始化时都会自带密码校验插件validate_password它会对用户密码的字母大小写、数字、符号、长度做综合评分。但这个插件在内部测试环境里很招人烦比如你只想设一个mysql123它直接拒绝。查看当前密码策略SHOW VARIABLES LIKE validate_password%;调整或者卸载这个插件可以直接在MySQL命令行里操作INSTALL PLUGIN validate_password SONAME validate_password.so; UNINSTALL PLUGIN validate_password;或者不卸载插件仅调整策略级别和长度阈值SET GLOBAL validate_password_policy LOW; SET GLOBAL validate_password_length 6;这些值在重启后可能会失效永久修改需要写进my.cnf配置文件里。生产环境我建议保留密码策略但设置成中等级别就够太苛刻的策略会逼着业务方把密码写在代码注释里反而更不安全。4.3 创建业务账号和远程访问控制root账号默认只允许localhost登录这本身是安全设计日志和权限审计时root的操作记录也更容易追溯到服务器层面。但业务需求不讲道理外部应用服务器IP连进来的情况太常见了授权方式需要分两类处理。第一类是纯内网应用账号授权时尽量限制IP段CREATE USER app_user10.0.0.% IDENTIFIED BY AppUserPass123; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO app_user10.0.0.%;第二类是运维管理账号也需要从堡垒机跳转登录的场景可以把host指定为堡垒机IP权限范围按需给。上面这种按权限最小化原则分配账号的方式比直接把root开放远程要安全得多。生产环境我从来不开放root远程登录这是底线级别的防火墙纪律。远程连接的端口要在系统防火墙里放行CentOS 7用firewall-cmdfirewall-cmd --permanent --add-port3306/tcp firewall-cmd --reload如果防火墙开着但你没放行端口本地连MySQL没问题远程连接会一直卡在连接超时状态这是非常经典的初级坑。4.4 生产环境不可忽视的几组MySQL参数配置和账号这些都搞定后再来看性能相关的参数。默认安装的MySQL参数主要照顾兼容性很少针对你的硬件做优化如果直接放到生产环境跑高并发时会很难受。以生产常用的4核8G内存服务器为例我会优先调整下面几组参数[mysqld] innodb_buffer_pool_size 2G innodb_log_file_size 256M innodb_flush_log_at_trx_commit 1 max_connections 500 slow_query_log 1 slow_query_log_file /data/mysql/logs/slow.log long_query_time 2 binlog_format row server-id 1innodb_buffer_pool_size是InnoDB最重要的缓存参数官方建议设为物理内存的50%到70%。8G内存设2G属于比较稳健的起步值如果你确认机器只跑MySQL可以往上调到4G。innodb_log_file_size影响写入性能5.7默认是48M业务高峰期会产生频繁的redo日志切换我一般调到256M起步。慢查询日志非常关键记录超过2秒的SQL后面做性能排查会省力很多。binlog_format row和server-id 1这两行是为后续做主从复制预留的。即使你现在只有一个库先把binlog开起来也没有坏处后面想搭建从库就自然水到渠成。改完参数不要忘了重启MySQL重启之后用SHOW VARIABLES确认参数已经生效。5. 常见问题排查与避坑实录最后这部分整理的都是过去几年里我踩过、见过、帮人扛过的经典现场。全部以具体问题为线索展开方便你遇到时直接对号入座。5.1 启动失败的几种典型原因启动失败算是最常见的故障类别。有人执行systemctl start mysqld之后卡在很长时间没反应然后再查状态发现failed。这时候一定先去日志文件里看究竟是哪一步出了问题。第一个高频原因是datadir权限不对。mysqld进程以mysql用户身份运行但数据目录的属主如果还是root初始化时就会报错类似“Unable to lock ./ibdata1: Permission denied”。在自定义datadir场景下目录要记得chown mysql:mysql这个在前文已经强调过别忽略。第二个原因是socket路径不一致。客户端连localhost的时候走的是socket文件如果my.cnf里写的是/tmp/mysql.sock但默认客户端配置里找的是/var/lib/mysql/mysql.sock就会出现“Cant connect to local MySQL server through socket”的报错。这种情况最简单的排查方式就是mysql客户端命令后面显式指定socket路径mysql -uroot -p -S /tmp/mysql.sock第三个原因是SELinux的拦截。CentOS默认SELinux是enforcing模式mysqld想写非标准的数据目录时会被安全策略直接拦下。遇到这种诡异问题可以先看SELinux日志或者直接尝试临时关闭SELinux验证排除setenforce 0如果关闭SELinux后服务能跑起来再考虑给MySQL目录添加合适的SELinux上下文而不是长期关闭SELinux。生产环境中我建议保留SELinux开启但给mysql目录设置正确的semanage标签。5.2 密码、认证和远程连接类问题配置好MySQL后本地能连远程连不上是高频问题。原因远远不止防火墙一个还有一个非常隐蔽的地方是bind-address。默认情况下MySQL的my.cnf里如果没有显式写bind-address那监听地址是0.0.0.0所有网卡都会监听。但如果在配置文件里写了bind-address127.0.0.1即使防火墙开了3306端口外部依然连不进来。跑到服务器上用netstat看一眼最直接netstat -lntp | grep 3306如果看到监听在127.0.0.1:3306说明配置问题如果是0.0.0.0:3306再去排查防火墙和用户权限。另外8.0版本默认使用caching_sha2_password认证插件很多老客户端比如Navicat旧版、PHP 5.x的mysqli扩展并不支持会报“Authentication plugin caching_sha2_password cannot be loaded”的错误。解决方法是把账号的认证方式改成mysql_native_passwordALTER USER root% IDENTIFIED WITH mysql_native_password BY YourPassword;这个兼容性问题在跨版本升级时特别值得注意老项目升8.0之前最好先全面盘点一遍客户端驱动版本。5.3 磁盘满了、日志爆了这类存储问题数据目录所在分区如果被写满MySQL的表现为写入报错SELECT还能跑INSERT直接卡住错误日志里大量出现“No space left on device”。建议用df -h先看整体空间情况再用du -sh /data/mysql/*定位具体哪个目录占用大。很多情况下罪魁祸首是binlog日志。如果主从没搭或者binlog一直没清理它会一直累积到磁盘撑爆。在5.7中可以通过以下方式刷新并清理mysql -uroot -p -e PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;更根本的做法是配置文件里加上binlog过期时间expire_logs_days 7 max_binlog_size 256M在8.0里这个参数改名叫binlog_expire_logs_seconds如果你用8.0注意参数名称的差异。关于热词里提到的“不重启扩容”这里给一个实用经验如果系统用了LVM数据盘空间吃紧时配合lvextend和xfs_growfs/resize2fs可以实现在线扩容不需要重启服务。CentOS 7默认用的xfs文件系统扩容命令略有讲究。先给逻辑卷扩容再执行xfs_growfs /dev/mapper/centos-home文件系统扩大后MySQL的数据目录还在原挂载点直接继续用数据库进程完全不用重启。这个技巧在线上环境很实用出现磁盘告警可以快速应急而不影响业务。5.4 在Docker里装MySQL失败要不要转原生安装最近总有人问我“Docker装MySQL是不是有什么坑我照着教程执行完容器起不来到底是哪里出了问题”每个问这个问题的人我都建议先看看是不是下面三个通病。第一个是容器内MySQL的数据权限问题。镜像默认用mysql用户但宿主机挂载的数据目录如果属主是root容器内mysql用户没有写权限初始化阶段就会失败。解决办法是挂载目录先chown 1000:1000或者设置为777再重启容器。第二个是容器日志无限增长。Docker容器日志如果没做轮转限制MySQL这种每天写大量慢查询和错误日志的进程会把几十GB的json日志文件堆在/var/lib/docker/containers目录下。解决方案是给容器加日志轮转参数或者在Docker daemon配置里统一限制。第三个是容器内时区、字符集、内核参数这些细微差异。时区默认UTC查询NOW()和业务时区对不上字符集默认不一定支持utf8mb4。不是说Docker不能跑MySQL而是如果你对这些细节理解不够深Docker方案的上手成本反而更高。我的建议很明确如果只是为了本地开发跑一跑Docker是够用的如果是生产环境或者对稳定性要求高原生安装依然是更稳妥的路线。热词里大面积出现docker安装mysql失败说明遇到过问题的人并不是少数这时候转原生安装往往能一步到位解决掉一揽子问题。5.5 字符集问题出现中文乱码的根因还有个问题几乎每个做业务的人都会碰到插入中文后查询出来是一堆问号。出现这种问题核心原因就是字符集没有统一。MySQL字符集涉及三个层客户端连接层、服务端默认层、表和字段层。检查当前环境SHOW VARIABLES LIKE character_set%;如果看到character_set_server是latin1而业务数据是中文后端接口很容易出现编码错乱。统一改成utf8mb4的方式很简单配置文件写入[mysqld] character-set-serverutf8mb4 collation-serverutf8mb4_general_ci [client] default-character-setutf8mb4已经建好的表也需要单独转换ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;注意如果表里已经有乱码数据单纯转字符集并不能把乱码修复必须先排查数据写入链路每一步的编码是否统一从应用层到数据库连接串再到表结构。我看过太多人在字符集上反复折腾最后发现只是应用连接串里没加characterEncodingutf8mb4这一类属于应用层的编码统一问题。我的安装顺序和一点经验如果要我在一台全新的CentOS机器上从头装MySQL操作顺序一定是先确认版本需求然后检查并清理历史残留数据库配置对应版本的MySQL repository优先yum安装。如果yum方案因为网络或者版本限制走不通立刻切换到tar包二进制安装配置最小可用的my.cnf完成数据目录初始化和systemd接管最后统一做账号权限和数据目录规划。这个顺序培养了几年基本能覆盖我遇到的所有场景。最后补一个容易忽略的细节每完成一步重要配置比如初始化密码、调整密码策略、创建业务账号都最好在本地留一份带时间戳的操作记录和当前配置文件的注释版本。别等三个月后数据库出了安全问题才回溯那时候你已经想不起来当初改了哪些默认值了。经验越往后越值钱其实就在于这些细节沉淀。