ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MySQL 8 二进制安装实战:从下载解压到 systemd 托管与安全加固

MySQL 8 二进制安装实战:从下载解压到 systemd 托管与安全加固 mysql8 的二进制安装是很多生产环境里最常用、也最容易被轻视的一种部署方式。不提 yum 源、不搞源码编译直接把官方编译好的通用二进制包拉到指定路径靠 my.cnf 和几条初始化命令把实例拉起来。这种方式在离线内网、统一版本管控、多实例部署这些场景里非常顺手也是我这些年处理 MySQL 问题时最常复现环境的手段。这篇文章我会用 CentOS 7 系环境、MySQL 8.0.36 版本为例把二进制安装的全过程拆开讲清楚包括下载解压、目录规划、my.cnf 参数、初始化命令、systemd 托管启动、账号安全还有我踩过的几个坑。Windows 下那种免安装 zip 包其实也属于二进制分发我会在最后单独说几句。1. 为什么要用二进制安装而不是 yum 或者源码编译1.1 三种安装方式的核心差异先聊清楚一个很多人搞混的问题yum 装的 MySQL、源码编译的 MySQL、二进制包安装的 MySQL到底差在哪yum 安装走的是发行版仓库或官方 yum 仓库好处是依赖自动解决、升级方便但坏处也很明显——你没得选。仓库里是什么版本就是什么版本编译参数也是别人定好的。比如某些发行版把INNODB的页面大小、字符集默认值改过你在生产环境排查问题时行为跟官方文档对不上就会很头疼。源码编译是最灵活的方式可以精确控制编译选项、裁剪功能模块但代价是编译时间长一般要 20 到 40 分钟、依赖一大堆开发库、出错概率也高。除非你要做二次开发、或者对特定硬件平台做优化否则在生产环境为了装个数据库去编译源码性价比很低。二进制安装正好卡在中间。官方在编译二进制包时用的是一套经过充分测试的默认配置你拿到手就能跑不需要处理编译期的依赖问题同时版本完全可控、目录完全可控、启动方式完全可控。你要做的只是把文件解压到指定目录然后自己写配置、自己初始化数据目录。对于大多数场景这个方案最合适。多实例部署时尤其明显——你想在一台机器上跑两个 MySQL 8端口分别是 3306 和 3307yum 装的那套做起来很别扭但二进制包想放几个放几个。1.2 哪些场景必须用二进制安装我遇到过这么几类场景二进制安装基本上是唯一解第一内网离线环境。生产区的机器往往不连外网yum 源是内网镜像版本滞后且不一定有 mysql8。你拿一个二进制 tar 包拷贝进去解压就能用不依赖任何网络操作。第二多版本共存。业务还没完成升级老库跑着 MySQL 5.7新库要用 8.0同一台机器上两个版本并存。用 yum 装的话版本冲突问题能把你绕晕二进制包各放各的目录互不干扰。第三标准化交付。公司内部有统一的 MySQL 部署规范要求 basedir、datadir、日志路径都是固定位置配置文件统一模板。二进制包是最容易做出标准化脚本的安装方式。搞清楚了为什么下面就直接上手操作。2. 安装前的环境准备与文件规划2.1 系统依赖与检查清单很多人在二进制安装时遇到的第一道坎是初始化直接报错找不到共享库。MySQL 8 对操作系统的依赖其实很少但有几个东西必须先确认。在 CentOS 7 上先检查这几个依赖包是否已安装yum install -y libaio numactl-libs ncurses-compat-libslibaio必装MySQL 用异步 IO 就靠它之前很多人在初始化时报libaio.so.1找不到就是少了它。numactl-libs和ncurses-compat-libs在某些精简系统上也会缺顺手装上能省很多事。接下来检查系统里是否有残留的 MySQL 或 MariaDBrpm -qa | grep -i -E mysql|mariadb如果有先用rpm -e --nodeps卸载干净。之前见过一台机器上装了 MariaDB 的库文件结果 MySQL 的 socket 文件和它冲突初始化成功了却起不来服务排查半天。然后检查 3306 端口是否被占用ss -lntp | grep 3306这一步容易忽略但很重要。很多新手在启动时报Bind on TCP/IP port: Address already in use原因就是别的进程占着端口。还有一点很多人没注意检查/etc/my.cnf是否存在。CentOS 7 的 mariadb-libs 会顺手装一个全局配置文件如果它存在后面 MySQL 启动时可能会读到这个残留配置导致行为异常。建议先看一眼有内容就先备份再清空避免干扰。2.2 下载 MySQL 8 二进制包并校验下载地址直接去 MySQL 官方下载页的 Community Server 区域选择 Linux - Generic这个就是官方通用二进制包。我习惯用国内镜像站下载比如华为云或者清华的镜像速度快很多还支持断点续传。以 8.0.36 为例文件名一般是mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz如果你的系统 glibc 版本很低CentOS 7 是 2.17选 glibc2.17 这个版本是兼容的。下载后建议做一下 SHA256 校验sha256sum mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz把输出结果跟官方页面上的 checksum 对比确认包没损坏也没被篡改。这一步在生产环境里是必须的别省。2.3 目录规划与用户创建我个人习惯的目录规划是这样BASE_DIR/usr/local/mysql # 软链指向实际版本目录 DATA_DIR/data/mysql/data # 数据文件目录 LOG_DIR/data/mysql/logs # error log、binlog、slow log 都放这里为什么不直接把解压目录当 basedir因为后续升级时只需要把新版本目录解压出来改一下软链指向数据目录不动回滚也方便。这个思路和很多应用的做法一样把程序和配置数据分离。解压并建立软链cd /usr/local tar -xvf mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz ln -s /usr/local/mysql-8.0.36-linux-glibc2.17-x86_64 /usr/local/mysql创建 MySQL 专用系统用户注意不要用 root 跑 mysqldgroupadd mysql useradd -r -g mysql -s /sbin/nologin mysql mkdir -p /data/mysql/data /data/mysql/logs chown -R mysql:mysql /data/mysql chown -R mysql:mysql /usr/local/mysql-r表示创建系统账户-s /sbin/nologin表示禁止登录这是安全基线别图省事给 mysql 用户一个 bash shell。/usr/local/mysql整个目录 chown 给 mysql 其实有点粗暴更精细的做法是只把data、logs等需要写权限的目录给 mysql程序目录保持 root 拥有。但很多生产环境图省事直接整个 chown目前看问题不大。严谨一点的话可以这样chown -R mysql:mysql /data/mysql程序目录仅保留执行权限后面运行时只有配置里指定的路径需要写。3. my.cnf 配置参数的选择与解读3.1 一份基础可用的 my.cnf二进制安装最核心的部分就是写配置。MySQL 8 的配置读取优先级是/etc/my.cnf、/etc/mysql/my.cnf、basedir/my.cnf等等为了让配置明确可控我会用--defaults-file来指定配置文件避免系统里残留配置干扰。下面这份配置是我多次生产部署验证过的基础模板[mysqld] # 基础路径 basedir /usr/local/mysql datadir /data/mysql/data socket /data/mysql/logs/mysql.sock pid-file /data/mysql/logs/mysql.pid log-error /data/mysql/logs/error.log # 端口与连接 port 3306 bind-address 0.0.0.0 max_connections 1000 max_connect_errors 100000 # 字符集 character-set-server utf8mb4 collation-server utf8mb4_0900_ai_ci # InnoDB 核心参数 innodb_buffer_pool_size 2G innodb_log_file_size 256M innodb_flush_log_at_trx_commit 2 innodb_flush_method O_DIRECT innodb_io_capacity 2000 innodb_io_capacity_max 4000 # binlog 与事务 server-id 1 log-bin /data/mysql/logs/mysql-bin binlog_format ROW binlog_expire_logs_seconds 604800 gtid_mode ON enforce_gtid_consistency ON # 其他 default_authentication_plugin mysql_native_password skip-name-resolve 1 lower_case_table_names 13.2 关键参数的选择理由这里挑几个容易踩坑的参数详细说说。character-set-server和collation-server为什么要这么配MySQL 8 的默认字符集虽然本来就是 utf8mb4但默认排序规则是utf8mb4_0900_ai_ci这个排序规则在老客户端和某些同步工具里兼容性不太好。如果你的应用要连接老版本客户端或者要跟 5.7 做数据迁移建议显式配成utf8mb4_general_ci。这个决定越早做越好因为表的排序规则在创建时定下来后期改非常麻烦。innodb_flush_log_at_trx_commit 2是我在生产环境比较常用的值。官方默认值是 1表示每次事务提交都把 redo log 刷到磁盘数据最安全但性能相对低。设为 2 表示每秒刷一次性能好很多崩溃时最多丢一秒数据。很多互联网业务能接受这个权衡。但如果是金融类业务请老老实实用默认值 1。default_authentication_plugin mysql_native_password是一个兼容性设置。MySQL 8 默认的认证插件是caching_sha2_password安全性更高但有一些老版本客户端比如 PHP 7.1 之前的 pdo_mysql、某些旧版 Navicat连不上。如果你确认客户端都支持新插件这个参数可以不设。设成mysql_native_password会让密码以旧格式存储安全强度稍弱但兼容性最好。我一般看项目情况新项目直接用默认老项目才改。lower_case_table_names 1要特别小心。它控制表名大小写是否敏感在 Linux 上默认是 0区分大小写Windows 上默认是 1不区分。如果确定未来要把数据从 Windows 迁移到 Linux或者反过来要在 Windows 上跑同样的库统一设成 1 能避免一堆找不到表的诡异报错。但这个参数必须在初始化数据目录之前就确定因为初始化之后就不能改了。我遇到过两个系统分别用了 0 和 1合并数据时表名大小写不一致简直灾难。innodb_buffer_pool_size的设置大小一个通用的参照是物理内存的 60% 到 70%。但要注意这是在只跑一个 MySQL 实例的前提下。如果同一台机器上还有别的应用或者跑多个实例就要分摊。比如一台 16G 内存的机器只跑 MySQL设 8G 到 10G 没问题如果要跑两个实例各自 4G 到 5G 比较稳妥。设太大反而会因为内存交换影响性能。4. 初始化数据目录与启动服务的完整实操4.1 初始化命令与初始密码获取配置写好了接下来是初始化数据目录。这一步用mysqld --initialize注意不是老版本熟知的mysql_install_db那个在 MySQL 8 里已经废弃了。/usr/local/mysql/bin/mysqld \ --defaults-file/etc/my.cnf \ --basedir/usr/local/mysql \ --datadir/data/mysql/data \ --initialize --usermysql这里有几个细节第一--initialize会生成一个临时 root 密码打印到 error log 里。初始化完成后立刻去看日志grep temporary password /data/mysql/logs/error.log输出类似这样[Note] A temporary password is generated for rootlocalhost: xxxxxxxx这个密码拿到手之后复制保存好一会儿要用的。第二初始化时--usermysql一定要带。不用 root 身份去跑 mysqld更不能用 root 去初始化数据目录否则生成的数据文件 owner 是 root后面启动服务时 mysql 用户没权限读写直接报错。第三--initialize有两种模式。默认模式和--initialize-insecure的区别在于前者生成随机密码后者生成空密码。生产环境必须用前者空密码的 root 账号哪怕只能本机登录也是安全隐患。4.2 使用 systemd 托管 MySQL 服务我不用mysqld_safe直接后台跑因为 systemd 现在已经是标准异常退出能自动拉起开机自启也方便。在/etc/systemd/system/mysqld.service写入[Unit] DescriptionMySQL Server Afternetwork.target [Service] Typeforking Usermysql Groupmysql PIDFile/data/mysql/logs/mysql.pid ExecStart/usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf ExecReload/bin/kill -HUP $MAINPID TimeoutSec300 PrivateTmptrue [Install] WantedBymulti-user.target然后重载服务并启动systemctl daemon-reload systemctl start mysqld systemctl enable mysqld检查启动状态systemctl status mysqld -l如果启动失败第一件事永远是用cat /data/mysql/logs/error.log看日志。比我见过很多人先去journalctl翻半天其实 MySQL 自己的 error log 里的报错信息要直观得多。4.3 登录并完成安全设置现在用前面拿到的临时密码登录/usr/local/mysql/bin/mysql -uroot -p第一次登录后MySQL 8 会强制要求先改密码才能执行其他操作执行ALTER USER rootlocalhost IDENTIFIED BY YourStrongPassw0rd!;密码复杂度要注意MySQL 8 的 validate_password 组件默认开启要求密码至少 8 位包含大小写字母、数字和特殊字符。你可以设置一个复杂的密码后续再根据安全策略调整。改完密码之后记得刷新权限FLUSH PRIVILEGES;到这一步一个单机 MySQL 8 实例已经可以正常使用了。本地测试一下/usr/local/mysql/bin/mysql -uroot -p -e SELECT VERSION();如果能看到 8.0.36 的版本号恭喜安装成功。5. 远程访问配置与安全加固5.1 创建远程登录账号MySQL 安装完成后默认的 root 用户只能从 localhost 登录这是安全策略别去改它。远程访问应该单独建账号CREATE USER app% IDENTIFIED BY AppPassw0rd!; GRANT ALL PRIVILEGES ON appdb.* TO app%; FLUSH PRIVILEGES;app%表示这个账号可以从任意 IP 登录。如果业务服务器 IP 固定强烈建议收紧为类似app192.168.1.%只允许内网网段访问降低暴露风险。还有一个细节是skip-name-resolve 1的影响。这个参数启用了之后MySQL 不会把连接的 IP 反解析成主机名这意味着授权时不能用applocalhost.localdomain这种主机名形式只能用 IP。如果你在配置里加了skip-name-resolve授权语句里写主机名会匹配不上报Access denied。要么全用 IP要么去掉这个参数。5.2 防火墙与系统的配合MySQL 装好了账号也建好了但远程连不上十有八九是防火墙没放行。CentOS 7 用 firewalldfirewall-cmd --permanent --add-port3306/tcp firewall-cmd --reload如果你用的是云服务器除了系统防火墙还要检查安全组的入站规则3306 端口是否放行。这里多说一句bind-address 设为0.0.0.0后MySQL 会监听所有网卡的 3306 端口。如果机器有公网 IP一定要确认防火墙规则足够严格只允许业务网段访问千万别把 3306 直接暴露到公网不然用不了几个小时就会被扫描爆破。5.3 日常管理的几个常用检查指令安装完成后建议立刻跑一遍下面这几条命令确认实例状态正常# 查看实例运行状态 /usr/local/mysql/bin/mysqladmin -uroot -p status # 查看关键配置是否生效 /usr/local/mysql/bin/mysql -uroot -p -e SHOW VARIABLES LIKE innodb_buffer_pool_size; # 查看监听状态 ss -lntp | grep 3306 # 查看错误日志中是否有异常 tail -f /data/mysql/logs/error.log把这些记到部署文档里每次安装完都要执行一遍形成肌肉记忆。等出问题才去查日志不如一开始就确认所有参数都符合预期。6. 常见问题与排查技巧实录6.1 初始化报错找不到共享库这是我见过频率最高的错误。执行mysqld --initialize时报错mysqld: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory这是典型的缺少libaio依赖。解决很简单yum install -y libaio装完再初始化就好了。有时候还会报libnuma.so.1找不到一样处理装numactl-libs。6.2 启动失败Access denied for user mysql这个报错通常出现在系统日志里[ERROR] [MY-010457] InnoDB: ./ibdata1: write error [ERROR] [MY-011971] InnoDB: Unable to lock ./ibdata1基本可以判定是数据目录权限问题。确认一下ls -ld /data/mysql/data如果 owner 不是 mysql执行chown -R mysql:mysql /data/mysql再启动。这个坑我踩过不止一次每次都是因为初始化的时候忘了带--usermysql导致数据文件 owner 是 root。所以初始化命令里--usermysql一定不能省。6.3 远程连接报 1130 错误错误信息ERROR 1130 (HY000): Host 192.168.1.100 is not allowed to connect to this MySQL server说明 MySQL 拒绝了来自该 IP 的连接。排查步骤先确认 MySQL 里的用户表SELECT user, host FROM mysql.user WHERE userapp;看 host 是否是%或者包含你连接源的 IP。不是就重新授权。再确认防火墙firewall-cmd --list-ports最后确认 bind-address。如果配置里是127.0.0.1外部 IP 根本到不了 MySQL 这一层改配置然后重启。6.4 改了配置参数不生效很多人改了 my.cnf重启服务后SHOW VARIABLES查出来还是旧值。原因基本都是参数写错了位置或者配置文件没被读到。MySQL 8 的参数分全局、会话两层部分动态参数可以用SET GLOBAL在线改但有些参数必须在启动时指定。比如innodb_buffer_pool_size是只读参数只能通过配置文件修改后重启生效。另外注意如果系统里有多个 my.cnfMySQL 会按优先级读取最后一个。不确定读的是哪个就用--defaults-file强制指定一劳永逸。6.5 忘记密码时的处理办法这个场景每个 DBA 都遇到过。办法是先用--skip-grant-tables跳过权限表启动systemctl stop mysqld /usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf --skip-grant-tables --skip-networking 注意--skip-networking很重要跳过密码验证的同时禁用 TCP 连接避免被外部访问。然后登录/usr/local/mysql/bin/mysql -uroot清空密码并恢复正常登录FLUSH PRIVILEGES; ALTER USER rootlocalhost IDENTIFIED BY NewStrongPassw0rd!;改完密码后重启服务kill $(cat /data/mysql/logs/mysql.pid) systemctl start mysqld这种方式适合应急不建议日常使用。7. 关于 Windows 下免安装版的一些补充搜索热词里频繁出现 mysql8 windows安装、mysql8免安装版本配置方法这里也多说几句因为 Windows 的 zip 包本质上也是一种二进制分发。Windows 下载页面选 Windows (x86, 64-bit), ZIP Archive解压后目录结构和 Linux 版几乎一致但没有mysql用户的概念也不需要初始化用户。手动创建一个my.ini放到解压目录下或者C:\ProgramData\MySQL\内容类似[mysqld] basedir C:/mysql-8.0.36-winx64 datadir C:/mysql-8.0.36-winx64/data port 3306 character-set-server utf8mb4注意 Windows 下路径分隔符用正斜杠或者双反斜杠单反斜杠会被当成转义符。初始化命令在 Windows 的 cmd 中执行mysqld --initialize --console执行完会在控制台直接打印初始密码。然后注册服务并启动mysqld --install MySQL8 net start MySQL8注意 Windows 版默认lower_case_table_names为 1表名不区分大小写。如果你在 Windows 上创建的库要迁移到 Linux表名全是小写那就没问题但凡混用了大小写到 Linux 上就会疯狂报错。这是个非常常见的坑提前知道能避免很多麻烦。另外 Windows 服务注册之后会以 MySQL8 这个服务名出现在服务管理器里开机自启默认开启跟 Linux 下 systemd enable 的效果一样。但有两点和 Linux 不同一是不能通过 systemd 的方式查看日志要看 error log 文件二是 Windows 下的--defaults-file路径中包含空格时需要给整条命令加引号否则服务启动会失败。用 zip 包在 Windows 上装 MySQL 8 做本地开发环境整体来说比 Linux 简单不少但生产环境跑 Windows MySQL 的场景很少这里不展开。8. 我的几个实操建议安装 MySQL 8 本身不是难事难的是安装完之后的长期维护。有几个细节是我实际操作中吃过亏之后才形成的习惯。第一数据目录和日志目录一定要独立分区。程序文件可以跟系统盘放一起但数据文件要放在单独的数据盘上。这样系统盘故障重装不影响数据备份和扩容也方便。如果条件允许日志文件binlog、redo log放在单独的盘上跟数据文件分开IO 竞争会小很多。第二所有部署操作尽量脚本化。我通常会把安装过程写成一个脚本传入版本号、端口、数据目录这些变量几秒钟就能部署一个新实例。脚本化之后每台机器上的部署动作完全一致排查问题的时候就少了很多机器差异带来的干扰。第三升级之前一定全套备份。二进制安装的升级相对简单解压新版本目录停掉旧实例切换软链启动新实例然后跑mysql_upgrade其实 MySQL 8 在启动时会自动检查并升级系统表。但整个过程有风险如果数据字典升级失败回滚就麻烦了。所以在升级前至少要做一次逻辑备份或者物理备份别嫌麻烦。第四初始化时的 root 临时密码日志里打印出来之后建议复制到一个密码管理工具里。我之前有一次初始化完忘记保存日志又被 logrotate 转走了只能走--skip-grant-tables那条路重置密码多花了不少时间。二进制安装这个技能看起来就是个基础操作但实际用好了能让你在面对各种环境时都游刃有余。上面这些内容和坑都是我亲手趟过来的希望能帮你少走点弯路。
返回列表