绝大多数做后端开发或者自己折腾服务器的朋友,迟早都会碰到同一个活儿:在 Linux 上装 MySQL。尤其是 CentOS,它长期霸占着国内服务器市场的装机量榜首,很多公司的生产环境到现在都还是 CentOS 7 或者它的兼容分支。而这篇文章要解决的,就是“CentOS 上安装 MySQL”这件事。我会把从零开始、到能安全跑起来的完整过程拆开揉碎,包括环境准备、版本选择、yum 安装、初始化配置、常见坑,尽量让刚上手的朋友少走弯路,也让已经装过的人能查漏补缺。
为什么值得花时间看这篇?因为 MySQL 安装这件事,网上教程其实非常多,但大多数要么只讲“复制粘贴命令”,要么默认你已经懂 Linux 基础。我这些年帮同事、帮学员处理过太多安装问题,发现真正的坑往往不在 yum install 这一步,而在装完之后。端口没开、密码策略搞不懂、字符集不对、权限配错,任何一个都能让你折腾一晚上。所以这篇文章会从实操角度,把完整链路走一遍,并特别说明哪些地方容易出问题、为什么。
适合谁来读呢?刚入行的运维、后端开发、自己搭博客或小型项目的爱好者,还有那些第一次在 CentOS 上部署服务的同学。我尽量让每一个命令、每一个配置项,你都知道它在干嘛,而不是无脑复制。
1. 装之前,先把思路理清楚
1.1 为什么是 CentOS + MySQL 这个组合
CentOS 之所以流行,和它的出身有很大关系。它是 Red Hat Enterprise Linux(RHEL)的社区编译版本,和 RHEL 保持高度二进制兼容。这意味着很多商业软件会优先针对 RHEL 系做适配,CentOS 自然跟着受益。再加上 yum/dnf 这套包管理机制非常成熟,安装软件、处理依赖关系都省心,所以大量服务器默认镜像就是 CentOS。
MySQL 则是开源关系型数据库里当之无愧的老大哥,社区活跃、文档丰富、生态完善,中小型项目用它基本不会错。组合在一起,就构成了国内很多团队最熟悉的一套基础设施。
不过这里要提醒一句:CentOS 7 已经在 2024 年 6 月正式停止维护了,这意味着它不再有安全更新。如果你是在生产环境,我建议要么尽快迁移到 AlmaLinux、Rocky Linux 这样兼容 RHEL 的发行版,要么至少把系统层面的安全补丁来源切换成这些社区的迁移方案。但本文的安装步骤在 CentOS 7 以及这些兼容发行版上都是通用的,你可以照做不误。
1.2 安装方式选型:yum 仓库 vs 编译安装 vs Docker
在 CentOS 上装 MySQL,主流方案有三条路线,我在实际工作里都试过,简单做个对比:
| 安装方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| yum/rpm 仓库安装 | 安装快、依赖自动处理、升级方便 | 版本可能偏旧(如果不加官方源) | 绝大多数场景,最推荐 |
| 编译安装 | 可定制编译参数、性能理论上最优 | 耗时长、依赖多、升级麻烦 | 特殊定制需求、研究学习 |
| Docker 容器 | 隔离干净、环境一致、启动秒级 | 数据卷和网络要搞明白,性能略打折扣 | 本地开发、微服务环境 |
对于绝大多数人,我强烈建议用第一种:添加 MySQL 官方 yum 仓库,然后用 yum 安装。理由很简单,官方仓库会帮你把版本、依赖、升级路径都管理好,你不需要手动处理那堆编译依赖。等以后 MySQL 出安全更新,直接 yum update 就能搞定,非常省心。
1.3 环境准备和前置检查
正式开始之前,有几个检查项建议你先过一遍,否则后面很容易在奇怪的地方卡住。
首先确认系统版本。执行cat /etc/redhat-release,正常会看到类似CentOS Linux release 7.9.2009 (Core)的输出。如果显示是 CentOS Stream、AlmaLinux、Rocky Linux,同样适用这篇文章。
然后是确认网络可以访问外网。因为我们要从 MySQL 官方源下载安装包,如果服务器在隔离的内网环境,后面那套 yum 安装流程就走不通。可以用ping -c 3 mirrors.tuna.tsinghua.edu.cn或者直接curl -I https://repo.mysql.com测一下连通性。这个问题我遇到过很多次,所以在安装之前先验证。
还有一个很多人忽略的点:CentOS 7 默认自带了 MariaDB 的依赖库。如果你之前用 yum 装过 mariadb-libs,后面安装 MySQL 时可能出现冲突,报错内容一般是file /usr/share/mysql/charsets/... conflicts between attempted installs。解决办法就是提前卸载自带的 MariaDB,命令是:
yum remove -y mariadb-libs注意,如果系统里已经有正在用的数据库数据,千万别直接卸载,先备份。实际操作中这句命令比较安全,因为正常新服务器上没数据。
1.4 选 MySQL 8.0 还是 5.7
这是安装前必做的另一个决定。MySQL 8.0 推出已经好几年,功能、稳定性、性能都成熟了,是当前的首选。相比 5.7,8.0 在默认字符集、窗口函数、CTE(公共表表达式)、性能监控等方面都有明显改进。
但也提醒一下:8.0 的默认认证插件是caching_sha2_password,而很多老版本客户端(比如 5.x 的 JDBC 驱动、老版本的 PHP mysqli)不支持,连不上会报认证错误。如果你要兼容老程序,要么在创建用户时指定mysql_native_password,要么直接用 5.7。新项目无脑选 8.0,老项目根据客户端情况评估。
2. 完整安装流程拆解
2.1 添加 MySQL 官方 yum 仓库
我们可以直接用 rpm 命令安装 MySQL 官方提供的仓库配置文件。这个 rp 包本身很小,只是帮 yum 增加一个指向 MySQL 官方源的配置文件。
# 安装仓库配置包 rpm -ivh https://repo.mysql.com/mysql80-community-release-el7-7.noarch.rpm如果你需要安装 5.7,可以考虑用对应的mysql57-community-release-el7-11.noarch.rpm。安装成功后会生成/etc/yum.repos.d/mysql-community.repo和mysql-community-source.repo两个文件。
这里有一个细节:默认情况下,mysql80-community是 enabled 状态,也就是说你直接 yum install 会装 8.0。如果你之前装过别的版本或切换过源,建议执行一下这个命令确认启用的仓库:
yum repolist enabled | grep mysql输出应该能看到mysql80-community/x86_64。如果想切换版本,可以用yum-config-manager工具来 enable/disable,也可以直接编辑 repo 文件里对应段的enabled=0/1,这个需要大家理解。
2.2 正式安装 MySQL 服务端
仓库配好之后,安装就变得很简单:
yum install -y mysql-community-server这个命令会安装 MySQL 服务端、客户端以及一些共享组件。如果是 8.0 版本,默认安装的是mysql-community-server和mysql-community-client,安装时间受网络影响,一般几分钟内完成。
装完之后可以顺手查一下版本:
mysql --version正常会输出mysql Ver 8.0.36 for Linux on x86_64 (MySQL Community Server - GPL)之类的信息。看到版本号,说明安装核心已经完成。
2.3 启动服务并设置开机自启
CentOS 7 使用 systemd 管理服务,命令如下:
# 启动 systemctl start mysqld # 设置开机自启 systemctl enable mysqld # 查看状态 systemctl status mysqld启动成功的话,status 里会是active (running),同时能看到进程 PID。这一步如果失败,不要慌,90% 以上是数据目录权限或者配置文件有问题,后面的排查章节会专门讲。
顺便说一句,我见过很多新手在启动服务后直接敲mysql -uroot,然后发现进不去,这其实是正常的,因为 8.0 在初始安装时会生成一个临时密码,你要先把它找出来,这个下面立刻就会讲。
2.4 获取临时密码,完成首次登录
MySQL 8.0 在初始化数据目录时,会自动为 root 用户生成一个临时密码,并且写在错误日志里。错误日志默认位置是/var/log/mysqld.log。我们用 grep 找出来:
grep 'temporary password' /var/log/mysqld.log输出像这样:
[Note] A temporary password is generated for root@localhost: Xxxx!yZa1b2C3d冒号后面那一串就是临时密码。注意这串密码一般比较“乱”,包含大写、小写、数字和特殊字符,复制时小心别漏掉结尾的标点。
登录命令:
mysql -uroot -p按提示粘贴临时密码,就能进到 MySQL 的交互界面。进去第一件事,改密码。因为 8.0 默认开启了 validate_password 组件,密码策略有一定强度要求,太简单的会直接拒绝。这里给大家一个能过的示例:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPass@2024';如果你不想那么复杂,也可以降低密码策略等级,这个我放到后面配置章节细讲。先记住一点:新装的 8.0,不把临时密码换掉,很多操作都做不了。
2.5 运行安全安装向导加固
MySQL 自带了一个安全加固脚本,叫mysql_secure_installation,交互式地把一些不安全项给你过一遍。执行:
mysql_secure_installation它一般会问这几个问题:
- 是否设置密码校验强度(VALIDATE PASSWORD COMPONENT)。
- 是否删除匿名用户。
- 是否禁止 root 远程登录。
- 是否删除 test 测试数据库。
- 是否刷新权限表。
我的建议是:第一个问题可以选 Y 但后面自己调整策略,也可以直接选 N,因为有些人本地测试不想被强度规则烦;匿名用户必须删;root 远程登录如果你有远程连接需求,这里先选 N 禁止,后面要开再用专门的命令开,这样更安全;test 库删掉;权限表刷新选 Y。
整个向导走完,MySQL 的基础安全状态就比较健康了。
3. 核心配置与上线前调优
3.1 my.cnf 里的关键参数
MySQL 的配置文件叫my.cnf,CentOS 上默认是/etc/my.cnf。很多教程会让你装完就改配置,但其实 MySQL 自己会用一组默认参数跑起来,只是有些参数不适合生产场景。我建议新装完、启动成功之后就先打开看看,了解现状,再根据需求改。
以下是一份适合小中型项目的起步配置,可以直接放到/etc/my.cnf的[mysqld]段下面:
[mysqld] port=3306 bind-address=0.0.0.0 datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock # 字符集 character-set-server=utf8mb4 collation-server=utf8mb4_0900_ai_ci # 连接数 max_connections=500 # InnoDB 缓冲池大小,建议设为物理内存的 50%~70% innodb_buffer_pool_size=1G innodb_log_file_size=256M # binlog server-id=1 log-bin=mysql-bin binlog_expire_logs_seconds=2592000这些参数是什么意思呢?port和bind-address控制监听的端口和地址,0.0.0.0表示允许所有网卡访问,如果只在本地用,改成127.0.0.1更安全。datadir是数据文件存放目录,一般不用动。character-set-server和collation-server是默认字符集和排序规则,我们统一用 utf8mb4,这样不管是中文、表情符号都能存。max_connections是最大连接数,默认 151 在并发稍高时会不够,但也不能拍脑袋调太高,每个连接都占内存,500对于一般应用足够。
innodb_buffer_pool_size是整个 MySQL 内存占用的大头,也是最重要性能参数。建议设为物理内存的 50%~70%。比如服务器 4G 内存,设 2G 合理;如果混跑 Web 应用和数据库,就不能分配太多,要预留内存给其他进程。innodb_log_file_size影响写入性能,太小时日志频繁切换,太大时崩溃恢复耗时变长。binlog相关配置主要给主从复制和数据恢复用,如果你只是一台单机,暂时不开也可以,但开了也不会有什么坏处。
改完配置之后重启服务:
systemctl restart mysqld重启后确认 MySQL 能正常起来,再敲mysql -uroot -p试试登录。配置文件语法错误会导致启动失败,日志里会有提示,遇到这种情况不要慌,先看日志。
3.2 字符集设置要仔细
很多人建完表插入中文,发现存进去是乱码,基本都是字符集没统一。MySQL 的字符集可以分几个层级:服务器级、数据库级、表级、字段级。当层级之间不一致时,可能会出现“字段是 utf8,但连接用的是 latin1”这类尴尬情况。
装完 8.0 后检查当前系统字符集:
SHOW VARIABLES LIKE 'character_set%';结果里character_set_server在 8.0 默认已经是 utf8mb4,而 5.7 默认是 latin1。为了统一,我习惯在建库时再显式声明一遍:
CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;如果是 5.7,排序规则一般用utf8mb4_general_ci。这样即使以后服务器级配置被覆盖,这个库本身不会回退到错误编码。
还要提一个很常见的坑:连接字符串里的编码。有些老程序在连接 MySQL 时没有指定 characterEncoding,导致客户端发送的 SQL 用系统默认编码,服务器端又按 utf8mb4 解析,两边一不一致就出乱码。这个一般在应用的数据库连接配置里加一行,比如 JDBC 的characterEncoding=utf8。数据库层面的设置只是基础,应用层面连接串必须跟上。
3.3 开放远程访问,但要保证安全
装完 MySQL 默认 root 只能在本地登录,如果你希望用 Navicat、DataGrip 等客户端远程连,需要做两件事。
第一,给用户授权远程访问权限。比如我创建一个专用的应用账号:
CREATE USER 'appuser'@'%' IDENTIFIED BY 'AppPass@2024'; GRANT ALL PRIVILEGES ON mydb.* TO 'appuser'@'%'; FLUSH PRIVILEGES;这里'%'表示允许任何 IP 连接。实际生产环境最好限制具体 IP,比如'appuser'@'192.168.1.100',不然等于把数据库裸奔在公网上,扫描到就是灾难。
第二,防火墙放行 3306 端口。CentOS 7 默认防火墙是 firewalld,检查状态并放行:
# 查看防火墙状态 systemctl status firewalld # 放行 3306,并重载 firewall-cmd --permanent --add-port=3306/tcp firewall-cmd --reload有的云服务器还要在安全组里单独放行 3306,这个属于云控制台操作,网页上处理一下端口入方向规则即可。有时候客户端还是连不上,我又查了半天,最后发现是云服务器的安全组没放行。
如果在内网环境,还涉及到 bind-address 的设置,前面配置文件里如果设的是127.0.0.1,远程连的时候就会报Can't connect to MySQL server on 'x.x.x.x' (10060),要把 bind-address 改成0.0.0.0或者具体内网 IP。
3.4 系统和文件句柄限制调整
MySQL 在并发连接比较高的时候,会打开大量文件句柄。Linux 默认的进程文件句柄限制是 1024,对于数据库进程来说很容易不够用。修改系统限制:
vim /etc/security/limits.conf文件末尾添加两行:
mysql soft nofile 65535 mysql hard nofile 65535然后重启 MySQL 生效。这个操作很多新手不知道,等到某一天数据库连接突然全部失败,dmesg里全是 “Too many open files” 才恍然大悟。调完这个限制,再配合前面的 max_connections,能撑住的并发就大不一样了。
另外要说一下 swap 的问题。如果服务器内存紧张,MySQL 进程可能会被换到 swap,性能会急剧下降。可以用free -h关注内存使用情况。临时关闭 swap 可以用swapoff -a,但生产环境一般不建议直接用交换分区来救急,最根本的方案是加内存或者合理控制 buffer pool 大小。
4. 常见问题与排查技巧实录
4.1 典型问题速查表
我在各种环境中装 MySQL,遇到最频繁的问题主要是下面这些。把它们按“症状、原因、解决方法”整理成一张表,方便你遇到问题时直接定位:
| 症状 | 常见原因 | 解决方法 |
|---|---|---|
Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' | mysqld 没启动,或 socket 路径不一致 | 检查systemctl status mysqld;确认 my.cnf 里的 socket 路径 |
Access denied for user 'root'@'localhost' | 密码错误,或临时密码已经失效 | 用临时密码登录后立即改密;忘记密码就用 4.3 节方法重置 |
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements | 密码强度不满足 validate_password 策略 | 提高密码复杂度,或调整 validate_password 策略 |
远程连接超时Can't connect to MySQL server (10060) | 3306 端口没放行,或 bind-address 限制 | 放行防火墙和安全组;修改 bind-address 为 0.0.0.0 |
| 中文乱码 | 字符集不一致 | 统一 server/database/connection 的字符集为 utf8mb4 |
Too many connections | 连接数达到 max_connections | 调大 max_connections,同时检查应用是否连接泄漏 |
Table doesn't exist但表实际存在 | 大小写敏感设置不一致 | Linux 下表名默认区分大小写,确认 lower_case_table_names 配置 |
这张表只是索引,具体细节往下看,我会挑几个展开说。
4.2 启动失败,如何从日志里找线索
遇到 MySQL 启动失败,最忌讳的就是瞎猜。先看两样东西:systemd 日志和 MySQL 错误日志。
# systemd 日志 journalctl -u mysqld -n 100 # MySQL 错误日志 tail -n 100 /var/log/mysqld.log常见启动失败的报错之一:
[ERROR] Can't start server: Bind on TCP/IP port: Permission denied这个报错一般说明端口被占用,或者 mysqld 没有权限绑定端口。用netstat -tlnp | grep 3306查一下是不是别的进程占用了 3306,也有可能之前有残留进程没杀干净。
另一个常见报错:
[ERROR] /usr/sbin/mysqld: Can't create/write to file '/var/run/mysqld/mysqld.pid'这是/var/run/mysqld目录不存在或权限不对,手动创建并给 mysql 用户:
mkdir -p /var/run/mysqld chown mysql:mysql /var/run/mysqld还有权限问题导致的失败:
[ERROR] Could not open required defaults file: /etc/my.cnf这通常是文件权限不对或路径写错,检查 /etc/my.cnf 是否存在、权限是否为 644 或更严格。实际操作中经常有人改配置文件时不小心改坏了语法,如少了分号或括号没配对,也会导致启动失败。这时错误日志里一般会提示哪一行有问题,跟着日志走就行。
4.3 忘记 root 密码忘了怎么办
这个场景我估计每个人都遇到过。给忘记密码的 MySQL 重置密码,推荐使用--skip-grant-tables方式,思路就是先绕过权限表启动 MySQL,再进里面改密码。
具体步骤:
# 先停掉 MySQL systemctl stop mysqld # 以跳过权限认证的方式启动 mysqld_safe --skip-grant-tables & # 这时候可以直接免密进入 mysql -uroot进入 MySQL 后,先刷新权限:
FLUSH PRIVILEGES;然后设置新密码。注意 8.0 的写法语法和 5.7 不太一样,8.0 是先修改加密规则再设密码:
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'YourNewPass@2024';改完之后退出,重启服务:
systemctl restart mysqld要特别提醒:--skip-grant-tables启动阶段,任何人都能免密登入,这非常危险,千万不要让这个状态暴露在公网环境中。操作完后一定要恢复正常启动。
4.4 监控和日常维护的几条经验
装好、调优完只是第一步,数据库是需要长期照看的。我自己的习惯是至少做这几件事:
第一,开启慢查询日志。默认慢查询日志是关闭的,把它打开能帮你抓到那些执行时间过长的 SQL,这是优化数据库最直接的依据。在 my.cnf 里设置:
slow_query_log=1 slow_query_log_file=/var/log/mysql-slow.log long_query_time=1这个配置的意思是:执行超过 1 秒的 SQL 都会被记录下来。刚开始不用设太长也不用太短,1 秒是比较合理的起点,等稳定了再根据业务调整。日志文件记得定期清理,或者交给 logrotate 处理。
第二,定期备份。备份这种事,临时想起来才做就等于没有。最基础的逻辑备份工具是 mysqldump,对中小库来说够用:
mysqldump -uroot -p --single-transaction --routines --triggers --events mydb > mydb_backup.sql--single-transaction参数对 InnoDB 表非常关键,它能在不锁表的情况下做一致性备份。恢复的时候执行:
mysql -uroot -p mydb < mydb_backup.sql第三,关注错误日志里定期出现的告警。比如日志中出现[Warning] InnoDB: page_cleaner ...之类的内容,说明数据库写入压力大或配置不匹配,尽早判断是不是需要扩容或调参。很多人安装完就把日志当成摆设,等到数据库卡死才去翻,那就晚了。
我个人还有个习惯:每次改完配置,都会在[mysqld]段里顺带写上注释,标注“改了哪个参数、为什么改、什么时候改的”。因为数据库这种长生命周期服务,时间一长没人记得当初为什么这么配,有注释能省掉很多推理成本。毕竟生产环境里,一个参数可能牵一发动全身,有据可查才算负责任。
文章到这里,从检查环境、添加源头、安装服务、初始化配置,到调优、排查、日常维护,基本把 CentOS 上安装 MySQL 的完整链路都过了一遍。这些方法都不是什么花活,而是我自己在服务器上反复踩过坑之后沉淀下来的日常工作流。按这个顺序来一遍,你得到的不只是一个能跑的 MySQL,而是一个你能掌控、知道它各个部分在干什么的 MySQL。