干了这么多年运维,MySQL 装过没有一千次也有八百次了,绝大多数时候解压官方二进制包就能完事。但这次接手一个内网新项目,安全基线要求目录结构全部自定义、需要集成特定的编译选项,还得在完全离线的环境下交付——二进制包这条路就堵死了,只能老老实实走源码编译这条路。
“源码包安装mysql8.0.43”这个事,说难不难,说简单也不简单。难点不在于敲命令,而在于环境依赖、CMake参数、Boost库版本这些坑你提前有没有踩过。这篇文章我把整个流程从环境准备、依赖安装、CMake配置、编译安装、数据初始化到systemd托管完整走一遍,把每一步的取舍和理由都说清楚,你照着做基本一次过。
1. 源码安装的前置思考:为什么非要折腾编译这条路
官方其实很贴心地提供了Linux通用二进制包(linux-glibc2.17-x86_64),解压、初始化、启动,三步走完。那为什么还有人在坚持源码编译?我这次的项目给了几个很现实的理由:
第一,目录规划受控。二进制包虽然可以通过basedir、datadir指定路径,但内部的文件布局是固定的。源码安装可以在CMake阶段就指定prefix,把二进制、配置、日志、数据彻底拆到不同目录,满足等保和审计要求。
第二,编译参数可以裁剪。比如不需要Archive、Blackhole这些冷门存储引擎,就在CMake阶段直接关掉;需要把SSL替换成系统OpenSSL、需要打开额外的性能监控选项,也只有源码编译能插得进去。
第三,离线交付的确定性。二进制包依赖系统的glibc版本,一旦目标机器系统版本太老,跑起来就会在启动阶段各种报错。源码包在编译机上把依赖全部静态链接或者按目标机环境编译进产物,交付给客户环境时反而更可控。
另外还有一个隐性问题——二进制包不一定跟进最新patch。像8.0.43这种小版本更新,如果你在source distribution页面找不到对应的linux tarball,那就只能等各发行版仓库的镜像更新,或者是自己编译。源码包的优势在这里就很明显:官方源码打个tag就能从GitHub或CDN拉下来,随时可以自己构建。
什么场景适合源码安装?我的经验是:定制化需求强、离线交付、对目录和库文件依赖有明确约束的。如果你的环境只是自己测试、随时能上网装软件,用官方二进制包或者系统仓库的包(yum/apt直接装)反而更快,没必要跟着受编译那份罪。想清楚了再动手,这是源码编译第一课。
2. 环境准备:把家底先摸清楚
2.1 系统与硬件要求
MySQL 8.0系列的源码编译对编译环境和运行环境都有硬性要求,满足不了就只能卡在开始。官方文档写的是GCC 7.1+,实际我编译8.0.43用的CentOS 7.9自带的GCC 4.8.2直接报错,后来升级到devtoolset-9才过。这一点必须提前排查。
硬件上,编译MySQL 8.0对内存和磁盘的消耗都比想象中大。完整编译一次大概需要2GB以上可用内存(4GB为推荐底线),磁盘空间至少准备10GB——源码包解压后约800MB,编译过程中产生的中间文件峰值能到好几GB。我之前在一台2GB内存的机器上编,make到一半直接out of memory,进程被OOM killer干掉,白白等了半小时。如果你是虚拟机或者小内存机器,建议加swap或者干脆换台机器编。
2.2 依赖包安装清单
以CentOS 7.9/8.x为例,编译MySQL 8.0.43需要的核心依赖有这些:
| 依赖 | 作用 | 缺失时的报错特征 |
|---|---|---|
| gcc / gcc-c++ | C/C++编译器 | compiler not found / C++17 not supported |
| cmake | 构建配置工具 | CMake Error: could not find cmake |
| make | 编译调度 | make: command not found |
| ncurses-devel | 命令行终端支持 | CMAKE reports curses library not found |
| openssl-devel | SSL/TLS加密通信 | openssl headers not found |
| libaio-devel | 异步IO支持 | libaio.h missing 相关错误 |
| pkg-config | 依赖发现工具 | Package xxx was not found |
| bison | 语法解析器生成 | Bison not found |
CentOS系的一般这样安装(联网情况下):
yum install -y gcc gcc-c++ cmake make ncurses-devel openssl-devel libaio-devel bison pkg-configUbuntu/Debian系对应的是:
apt install -y build-essential cmake libncurses-dev libssl-dev libaio-dev bison pkg-config注意:CentOS 7自带的cmake版本是2.8,完全不满足MySQL 8.0的要求(最低CMake 3.7,建议3.20以上)。所以yum装完之后大概率还得手动装一个新版cmake。我一般去cmake官网直接下载预编译的二进制包,放到/usr/local/cmake下,再把PATH指过去,能省去很多源码折腾。
2.3 编译账号与目录规划
MySQL服务端官方明确要求不允许用root账号直接运行mysqld,这是安全红线,也是启动时的一个硬检查。所以编译之前先把运行账号和目录结构定下来:
groupadd mysql useradd -r -g mysql -s /bin/false mysql mkdir -p /usr/local/mysql # 安装目录 mkdir -p /data/mysql # 数据目录 mkdir -p /var/log/mysql # 日志目录我通常把安装目录定在/usr/local/mysql,数据目录单独挂在/data分区下。这样以后扩容、备份、迁移数据目录都不会动到二进制文件,逻辑清晰。目录权限在编译安装完之后再统一chown给mysql用户,前期不用管太多。
还有个习惯性问题:很多人喜欢在/tmp下解压源码包。如果你机器/tmp被noexec挂载,后续CMake执行测试程序会直接Permission denied。这个坑我踩过一次,强烈建议源码包解压到/home或/opt这种普通目录下。
3. 源码下载与CMake配置
3.1 获取源码包并校验
源码包的获取渠道主要有两个:MySQL官网的Source Downloads页面,以及GitHub上的mysql/mysql-server仓库tag。因为离线环境的限制,我们一般提前在有网机器上下载好tar.gz包再拷进去。文件名类似:
mysql-8.0.43.tar.gz下载完成先做校验,和官方提供的MD5/SHA256比对一下。别嫌这一步麻烦,源码包被篡改的后果比二进制包严重得多——编译链接后你根本发现不了代码里被塞了什么。我习惯用sha256sum:
sha256sum mysql-8.0.43.tar.gz # 与官方页面提供的checksum比对,一致再继续解压:
tar -xzf mysql-8.0.43.tar.gz -C /opt/ cd /opt/mysql-8.0.433.2 关键的CMake配置参数
MySQL 8.0的构建系统和老版本完全不一样,它是用CMake驱动的,核心配置文件是源码根目录的CMakeLists.txt。所以我们不是在makefile里改参数,而是先用cmake命令生成makefile。
一个比较完整的CMake配置命令(离线环境推荐写法)长这样:
cmake . \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DMYSQL_DATADIR=/data/mysql \ -DSYSCONFDIR=/etc \ -DEFAULT_CHARSET=utf8mb4 \ -DDEFAULT_COLLATION=utf8mb4_0900_ai_ci \ -DWITH_SSL=system \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_ARCHIVE_STORAGE_ENGINE=0 \ -DWITH_BLACKHOLE_STORAGE_ENGINE=0 \ -DWITH_BOOST=/opt/boost_1_77_0 \ -DMYSQL_UNIX_ADDR=/tmp/mysql.sock \ -DCMAKE_BUILD_TYPE=Release逐个说下我用到的参数,让你知道每个选项背后在干什么:
- CMAKE_INSTALL_PREFIX:安装根目录,相当于二进制包的basedir。mysql、bin、lib、share这些子目录都会装到这个目录下面。
- MYSQL_DATADIR:数据目录的默认值。注意这个参数只是写进编译产物里的默认值,真正生效还是看my.cnf里的datadir配置,但是保持一致能省很多坑。
- DEFAULT_CHARSET / DEFAULT_COLLATION:默认字符集和排序规则。8.0里我推荐utf8mb4,配合默认排序规则utf8mb4_0900_ai_ci,能完整支持emoji和所有Unicode字符。
- WITH_SSL=system:使用系统自带的OpenSSL。如果你不想链接系统SSL,可以改成WITH_SSL=bundled让编译过程把OpenSSL源码一起编进去,但那种方式在目标机有新版本SSL漏洞时没法单独升级。
- WITH_BOOST:MySQL 8.0编译期强制依赖Boost库。直接用源码包里自带的boost download机制:加-DDOWNLOAD_BOOST=1 -DWITH_BOOST=/opt/boost,CMake会自动从网上拉指定版本。但在离线环境下downloader会失败,所以必须提前在有网机器下载好boost_1_77_0.tar.gz,解压到/opt/boost_1_77_0再指定路径。注意boost版本不是随便选的,要和这个MySQL小版本匹配,8.0.43对应的就是1.77.0。
提示:CMake配置最大的感受是“错过一个选项,编译到一半GG”。建议把cmake命令先写到脚本里存起来,后面改参数重新编译时仍然用的上。
3.3 编译安装产物生成
cmake配置成功后,源码目录下会生成Makefile。接下来直接make编译,根据机器核数开并行任务:
make -j4-j后面的数字建议不要超过CPU物理核数的1.5倍。在16核的机器上我会用-j8或者-j12,但在4核小机器上开到-j8很容易内存吃紧。整个编译过程在16核机器大约20到40分钟,在4核机器可能要一两个小时,中间会有非常多编译进度输出,看起来像死机但其实是正常的。
编译完成且无报错后执行安装:
make install安装完成后确认一下目录结构:
ls -l /usr/local/mysql/bin/mysqld /usr/local/mysql/bin/mysql --version如果版本号正确输出了8.0.43,说明编译产物没问题。这时把安装目录属主改给mysql用户:
chown -R mysql:mysql /usr/local/mysql我习惯把编译过程中的中间文件保留一段时间,等一到两周确认新实例完全稳定了再手动清理源码目录,这样如果后续要调整编译参数重新编译,不用重新解压下载一遍。
4. 初始化与配置文件:让数据目录真正“出生”
4.1 全局配置my.cnf怎么写
编译安装的MySQL默认不会主动读取源码包里的任何配置文件,它按顺序查找/etc/my.cnf、/etc/mysql/my.cnf等路径。我们既然在CMake阶段指定了SYSCONFDIR=/etc,就直接在/etc/my.cnf建配置。
我的最小可用配置模板:
[mysqld] basedir = /usr/local/mysql datadir = /data/mysql socket = /tmp/mysql.sock pid-file = /data/mysql/mysql.pid log-error = /data/mysql/error.log port = 3306 server-id = 1 character-set-server = utf8mb4 collation-server = utf8mb4_0900_ai_ci default_authentication_plugin = caching_sha2_password max_connections = 500几个配置项说明一下:basedir和datadir必须和实际安装路径、数据目录严格一致,拼错一个都起不来;socket路径影响客户端通过本地socket连接;log-error是排查启动问题第一看的地方;default_authentication_plugin用8.0默认的caching_sha2_password就行,这个插件从8.0.4开始就是默认的,兼容性完全没问题,不用像网上有些旧文章那样改回mysql_native_password。
注意:在8.0版本里,innodb_buffer_pool_size等参数没有配置时用默认值也能跑,个人测试环境完全不用堆一堆优化参数。很多编译安装一遍没跑起来,不是配置写得不够多,而是某些参数写错了路径或者冲突了。
4.2 数据目录初始化
8.0的初始化命令和5.7类似,但一定要注意顺序:先确保数据目录存在且为空,再由mysql用户执行mysqld --initialize。命令如下:
mkdir -p /data/mysql chown -R mysql:mysql /data/mysql /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --initialize-insecure --user=mysql这里我用的是**--initialize-insecure**而不是--initialize。两者的区别在于:--initialize会生成一个随机临时root密码,打印在error.log里;--initialize-insecure则生成一个root空密码账号。首次登录后都需要立刻改密码。我推荐用insecure方式,省去翻日志找密码的操作,适合内网环境。
初始化过程一般几秒钟就完事。完成后检查error.log末尾是否有明确错误,以及数据目录里是否生成了mysql、sys、performance_schema等系统库目录:
ls -l /data/mysql看到ibdata1、mysql目录、*.pem这些文件,初始化就成功了。注意整个数据目录必须保持属主是mysql,否则启动阶段会因目录权限问题直接退出。
4.3 启动验证与基础安全操作
先手动启动一次mysqld,确认基本功能正常:
/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf --user=mysql & sleep 5 /usr/local/mysql/bin/mysqladmin --socket=/tmp/mysql.sock ping如果返回mysqld is alive,说明服务端已经起来了。接着登录修改root密码:
/usr/local/mysql/bin/mysql --socket=/tmp/mysql.sock -u root -p由于初始化用的是insecure模式,root密码为空,直接回车就能登录。然后执行:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPass@2025'; CREATE USER 'app'@'%' IDENTIFIED BY 'AppPass@2025'; GRANT ALL PRIVILEGES ON appdb.* TO 'app'@'%'; FLUSH PRIVILEGES;这里提一个很多人容易忽略的点:MySQL 8.0的root默认只允许localhost登录,如果后续要通过远程IP管理这台数据库,必须显式创建'root'@'%'或专用管理账号,而且建议用app账号最小权限模型,别所有应用都怼着root用。
5. systemd托管:编译安装也得有“体面”的启停
5.1 编写服务文件
手动mysqld_safe启动只适合验证阶段,正式环境肯定要用systemd托管,这样开机自启、崩溃自动拉起、日志统一管理都安排上了。MySQL源码包本身是不带systemd service文件的(二进制包没有,编译安装也没有),得自己写。
在/etc/systemd/system/mysql.service写:
[Unit] Description=MySQL 8.0.43 Server After=network.target After=syslog.target [Service] Type=forking User=mysql Group=mysql PIDFile=/data/mysql/mysql.pid ExecStart=/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf ExecReload=/bin/kill -HUP $MAINPID PrivateTmp=false LimitNOFILE=65535 [Install] WantedBy=multi-user.target关键点说明:
- Type=forking:mysqld_safe启动后自身进入后台,PID文件由mysqld写入。systemd通过PIDFile来跟踪主进程。如果PID文件路径写错,systemd永远认为服务启动失败(尽管进程其实活着)。
- LimitNOFILE:MySQL连接数一高就需要大量文件描述符,systemd默认上限可能偏低,显式设置65535是常规操作。
- PrivateTmp=false:如果设为true,mysqld看到的/tmp和我客户端连接的/tmp不是同一个,socket文件会找不到。这个坑很隐蔽,网上搜“mysql systemd 启动失败 socket”热门答案里一大半是这个原因。
写完加载并启动:
systemctl daemon-reload systemctl enable mysql systemctl start mysql systemctl status mysqlstatus显示active (running)且没有报错信息,就算正式托管成功。
5.2 日常管理命令
托管之后日常操作全部走systemctl:
systemctl start mysql systemctl stop mysql systemctl restart mysql systemctl status mysql查看日志用journalctl配合error.log:
journalctl -u mysql -n 100 tail -f /data/mysql/error.log编译安装的MySQL和发行版自带的包管理版本在systemd上差别不大,但需要注意如果之前用mysqld_safe手动起过实例,systemd启动前要先把旧的mysqld进程清干净,否则端口被占用,systemd永远起不来还报一个莫名其妙的错误。
6. 编译安装过程常见问题排查
源码编译这条路,几乎每个人都会踩几个坑。下面整理的是我在8.0.43编译安装过程中真实遇到过的、以及网友群里高频出现的问题,做成速查表给你。
6.1 依赖缺失与版本不合规
| 问题现象 | 原因 | 解决 |
|---|---|---|
| CMake Error: could not find cmake | 没装或PATH不对 | 安装cmake 3.20+,检查PATH |
| Compiler not compatible (GCC 4.8) | 系统gcc过老 | 安装devtoolset-9并启用,或换Ubuntu 20.04+编译 |
| curses library not found | 缺少ncurses开发库 | 安装ncurses-devel / libncurses-dev |
| Could NOT find Boost | Boost路径/版本不对 | 下载Boost 1.77.0并指定WITH_BOOST路径 |
| OpenSSL headers not found | 缺少openssl开发库 | 安装openssl-devel / libssl-dev |
Boos这个值得单独说。我见过太多人在这一步卡住,报错信息类似“Could NOT find Boost (missing: Boost_VERSION)”或者版本检测不匹配。千万不要图省事随机下载一个Boost版本,MySQL 8.0.43要求的是1.77.0,版本高了低了都可能编译不过。最稳的方式是加-DDOWNLOAD_BOOST=1让CMake联网下载(网络允许的情况下),它会自动抓取对应版本。
还有个容易被忽略的是libaio。8.0在链接阶段需要libaio.so,编译时如果缺了会报类似“libaio.so.1: cannot open shared object file”的错误,安装libaio-devel就好。
6.2 编译过程挂掉
- internal compiler error:如果出现在gcc 4.8.2上,几乎可以断定是编译器太老导致。换gcc 9+重新编译就能解决。有时候也会是内存不足导致编译器进程异常,看dmesg有没有OOM记录。
- make过程中段错误崩溃:优先排查内存和swap,其次排查磁盘空间。df -h看下/opt或/usr/local所在分区是否被编译中间文件占满。
- Boost头文件编译报错:通常是Boost版本不匹配或者软链接冲突。删掉CMakeCache.txt重新执行cmake,强制重新检测依赖。
- CMake反复失败但看不到实质错误:把源码目录下的CMakeCache.txt删掉再重新cmake。这个文件会缓存上一次检测到的一堆路径和标志位,参数变了它却不更新,是你改了WITH_BOOST或WITH_SSL后最常出现的问题。
6.3 初始化与启动疑难
初始化阶段最常见的报错是“The designated data directory /data/mysql is unusable”。原因通常是目录非空、权限不是mysql、或者指定路径里存在不属于mysql的残留文件。处理方式:
rm -rf /data/mysql/* chown -R mysql:mysql /data/mysql # 再重新执行初始化的命令启动阶段如果发现进程闪退,第一动作永远是看error.log而不是瞎猜。我遇到过几次典型问题:
- SELinux拦截了mysqld对/data/mysql的访问,error.log里会有Permission denied字样,需要调整SELinux策略或者把数据目录放行。
- 端口被占用:改my.cnf的port,或者netstat确认3306是否被旧实例占用。
- PID文件路径与配置不一致:检查/etc/my.cnf里的pid-file必须和systemd文件里的PIDFile完全一致。
最后分享一个我踩过最深的坑:不要在make安装完成后马上把源码目录删掉。有一次我为了省磁盘空间,编译完就rm了源码包,结果第二天想查某个编译选项的默认值,只能重新下载整个包再查文档。更坑的是,如果你后续需要重新编译,没有源码目录的情况下还得从头解压、重新cmake,时间成本全搭进去。
MySQL 8.0.43源码安装这条路,核心并不是把命令背下来,而是理解每个环节在做什么:CMake阶段决定了这个MySQL“长什么样”,初始化阶段决定了数据目录“活不活”,systemd阶段决定了它能不能长期稳定运行。走完这一遍,后续再做定制化编译、内网交付,甚至帮别人排查编译问题,心里都有底得多。