简介:MySQL 5.7.40 在 Linux glibc2.12、x86_64 架构下的离线安装包,面向需要在无外网环境快速部署数据库的运维与开发人员,解决网络受限时无法在线安装的痛点。压缩包内共包含 379 个文件,大小约 646.59MB,主要文件类型包括 104 个 .h 头文件、89 个 .so 动态库、25 个 .xml 配置和 9 个 .sql 脚本,以及服务器守护进程、客户端管理工具、备份恢复程序等核心可执行组件,并附有默认配置模板与说明文档,目录结构与官方发行包一致,便于按需检索和权限核对。已有 748 人学习下载。该版本在 InnoDB 引擎、JSON 支持、TLS 加密方面表现稳定,包内整合了初始化脚本、安全加固工具和多种运维组件,解压即可构建可用的 MySQL 服务;对熟悉 Linux 的用户,直接依据清晰的模块布局即可完成参数配置、数据初始化与日常管理,是内网生产环境部署与学习 MySQL 5.7 的实用资源。
1. 拿到 mysql-5.7.40 离线包不等于装完数据库:先搞懂这个 tar.gz 到底是什么
很多从业者第一次接触 MySQL 离线部署时,都会以为把 mysql-5.7.40-linux-glibc2.12-x86-64.tar.gz 下载下来、解压、跑个 mysqld 就万事大吉。实际动手才发现,这个压缩包只是一个“二进制发行版”,里面既没有现成的数据目录,也没有初始化好的系统库,更不会自动帮你创建 my.cnf。它跟用 yum 或 apt 安装的最大区别在于:所有文件都集中在解压目录里,启动、初始化、权限、日志、socket 全都要自己管。这篇文章就是围绕这个离线包,讲清楚从解压到跑起一个可用实例的完整路径,包括参数怎么设、常见初始化失败的原因、以及如何把数据目录和日志目录拆到独立磁盘。适合正在做内网部署、机房交付、或想彻底摆脱包管理器依赖的人。
2. 离线安装的底层逻辑:为什么 glibc2.12 版本能跨发行版跑
2.1 glibc 版本与二进制兼容性
这个安装包名字里的glibc2.12指的是它依赖的系统 C 库最低版本。CentOS 6 系列自带的是 glibc 2.12,CentOS 7 是 2.17,Ubuntu 18.04 是 2.27。只要目标机器的 glibc 版本大于等于 2.12,这个二进制就能运行。反过来,如果你拿一个 glibc2.17 的包丢到 CentOS 6 上,会直接报/lib64/libc.so.6: version GLIBC_2.14 not found。所以选包时先执行ldd --version看目标机的 glibc,别只看系统是 CentOS 还是 Ubuntu。常见做法是:内网机器如果系统版本杂乱,统一用 glibc2.12 的包,向下兼容性最好。
2.2 解压前的环境检查清单
在动手之前,我一般会花两分钟确认三件事。第一,磁盘空间:解压后约 3.2GB,加上初始化后的数据目录、binlog、redo log,建议预留至少 10GB。第二,依赖库:这个包运行时需要libaio和libnuma,缺了会在初始化或启动时报错。用yum install -y libaio libaio-devel numactl或apt-get install -y libaio1 libnuma1提前装好,别等到 mysqld 启动失败再排查。第三,用户与权限:MySQL 官方文档和绝大多数生产环境都禁止用 root 直接跑 mysqld,需要单独建一个 mysql 用户。这三步做完,解压才有意义。
2.3 解压与目录规划的常见布局
解压本身很简单,但目录规划会直接影响后续维护。我通常把安装目录放在/usr/local/mysql,数据目录放到/data/mysql-data,日志目录放到/data/mysql-log。这样做的原因是:系统盘坏掉时数据还在独立磁盘上,而且/usr/local/mysql只读即可保护二进制文件不被篡改。命令如下:
# 解压到指定目录 tar -zxf mysql-5.7.40-linux-glibc2.12-x86-64.tar.gz -C /usr/local/ cd /usr/local/ # 重命名,去掉版本号,方便后续路径引用 mv mysql-5.7.40-linux-glibc2.12-x86-64 mysql # 创建数据目录和日志目录 mkdir -p /data/mysql-data mkdir -p /data/mysql-log # 创建独立的 mysql 用户(如果已存在会跳过) useradd -r -s /sbin/nologin mysql # 把目录所有权交给 mysql 用户 chown -R mysql:mysql /usr/local/mysql chown -R mysql:mysql /data/mysql-data chown -R mysql:mysql /data/mysql-log这段命令的逻辑是:先用-C指定解压目标,然后通过 mv 去掉版本号,后续所有配置和启动脚本都引用/usr/local/mysql这个固定路径。useradd -r创建的是系统账户,不能登录,符合最小权限原则。chown -R必须放在最后,因为 mv 和 mkdir 都可能改变目录属主。这里有一个容易被忽略的点:如果你之前用 root 在/data下建过目录,父目录/data本身如果权限是 755,mysql 用户是无法进入的,必须chmod 750 /data或者干脆/data也交给 mysql。
3. 初始化数据目录:mysqld --initialize 的参数与四个常见失败
3.1 使用 --initialize-insecure 还是 --initialize
初始化是整个离线安装中最容易翻车的一步。MySQL 5.7 提供了两个初始化选项:--initialize会生成一个随机 root 密码,并写在日志文件里;--initialize-insecure会生成一个空密码的 root 账号。对于内网交付,我建议先用--initialize-insecure,因为随机密码写日志后很容易被运维同事漏看,导致他们连不上就换数据目录重来。空密码模式下,启动后立刻用 socket 登录改密,反而更可控。初始化命令如下:
# 初始化数据目录,指定配置文件位置,使用 mysql 用户身份执行 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf \ --basedir=/usr/local/mysql \ --datadir=/data/mysql-data \ --user=mysql \ --initialize-insecure如果这一条命令直接结束没有输出,那是最理想的情况。它不会在终端打印成功信息,而是静默完成。你只需要确认/data/mysql-data下出现了mysql、sys、performance_schema这几个目录,就说明初始化成功了。参数说明:--defaults-file指定配置文件路径,注意这个参数必须写在最前面,否则后续命令行里的参数会覆盖配置文件里的值。--basedir和--datadir是告诉 mysqld 去哪里找二进制和放数据,如果 your my.cnf 里已经写了,命令行可以省略,但建议写上,因为初始化时有些配置文件还没生效,写成绝对路径最稳。
3.2 初始化失败:日志文件里藏着真正的答案
很多人在初始化报错后只看终端里那两行 ERROR,然后去网上搜,搜不到就怀疑包是不是坏了。实际上mysqld --initialize默认会在--datadir下生成一个hostname.err日志文件,报错的完整堆栈都在里面。我曾经遇到过一次报错[ERROR] InnoDB: Cannot open file ./ibdata1,终端上只显示一句“初始化失败”,而去翻日志才发现是/data/mysql-data的属主不对,mysql 用户没有写入权限。这种问题排查思路是固定的:初始化失败 -> 去 datadir 下找.err文件 -> 看最后 20 行。下面用一个常见失败案例说明排查过程:
# 模拟一个常见错误:忘记装 libaio 时的初始化输出 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf \ --basedir=/usr/local/mysql \ --datadir=/data/mysql-data \ --user=mysql \ --initialize-insecure # 报错可能长这样 # error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory # 解决方法是装依赖后重新初始化,不需要删除数据目录 # yum install -y libaio注意,如果你装完 libaio 重新执行初始化,之前失败的半成品数据目录可能会导致新错误。我一般会先rm -rf /data/mysql-data/*,把上次初始化留下的文件清空再跑。别心疼,初始化阶段没有任何需要保留的数据。还有一次,某同事在两台机器上分别初始化,一台报了[ERROR] Could not create file /data/mysql-log/error.log,原因是在 my.cnf 里指定了log-error,但日志目录的属主是 root,mysql 用户写不进去。解决很简单:chown -R mysql:mysql /data/mysql-log,然后重试。
3.3 my.cnf 的边界:哪些参数必须在配置里,哪些可以命令行临时override
初始化成功后,真正决定这个实例能不能长期稳定运行的是 my.cnf。新手喜欢把所有参数堆进去,实际上 5.7 版本推荐的最小配置只需要这么几块:
[mysqld] basedir = /usr/local/mysql datadir = /data/mysql-data socket = /data/mysql-data/mysql.sock pid-file = /data/mysql-data/mysql.pid port = 3306 log-error = /data/mysql-log/error.log这些参数是“物理路径类”的,必须跟你的目录规划一致。而innodb_buffer_pool_size、max_connections这类资源参数,我建议先跑默认值,等压测时再调。原因是 5.7 的默认配置在现代服务器上已经比较合理,贸然把 buffer pool 调大反而可能因为内存不足导致 OOM。另外注意socket和pid-file我写到了 datadir 里,这样做的目的是:如果服务器重启后数据盘没挂载,mysqld 启动会立刻失败,而不是把 socket 写到 /tmp 里造成假象。
3.4 启动与关闭:用 mysql.server 还是直接 mysqld_safe
初始化完成、配置文件就位后,启动实例的方法有三种。第一种是mysqld_safe,它会自动重启崩溃的 mysqld,适合排查阶段看日志。第二种是mysql.server start,本质是包装了 mysqld_safe。第三种是 systemd,但离线包默认不提供 service 文件,需要自己写。我建议前期调试用mysql.server,部署交付时改写成 systemd 管理。启动命令:
# 复制 mysql.server 脚本到 /etc/init.d/,改名方便识别 cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld # 启动 /etc/init.d/mysqld start启动后立刻确认三件事:端口有没有监听、socket 文件有没有生成、error.log 最后几行有没有报错。用ss -ltnp | grep 3306或者直接mysql -uroot -S /data/mysql-data/mysql.sock试连。如果启动失败,最有效的命令是直接前台跑:
/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --console前端输出会把所有错误直接打在终端上,比翻了半天日志快得多。看到ready for connections后再 Ctrl+C 停掉,切回后台方式启动。这一步我踩过坑:有一次前台跑能起来,mysql.server start就报错,最后发现是/etc/init.d/mysqld里没有读取/etc/my.cnf,因为脚本默认找/etc/my.cnf没错,但我的配置文件路径被写成了/data/my.cnf。解决方法是把脚本里的conf=/etc/my.cnf改成实际路径,或者干脆把配置文件放回/etc/my.cnf。
4. 连接与账号安全:首次改密、远程访问与最小权限配置
4.1 空密码登录后的强制改密流程
用了--initialize-insecure初始化后,root 用户没有密码。第一次登录后必须立刻改密,否则内网任何能连到这台机器的设备都能直接登进去。改密命令如下:
# 使用 socket 方式登录,避免 TCP 连接被网络层拦截 /usr/local/mysql/bin/mysql -uroot --socket=/data/mysql-data/mysql.sock # 登录后执行 ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPass2025'; FLUSH PRIVILEGES;这里有两个细节。第一,为什么用 socket 而不是-h 127.0.0.1?因为 socket 走的是本地文件,不经过 TCP 协议栈,即使防火墙限制了 3306 端口也不影响登录。第二,ALTER USER是 5.7 后推荐的方式,SET PASSWORD虽然还能用但已经标记为废弃。改完密码后,建议立刻测试一下用密码登录,确认无误再继续。否则改完密码又忘了,想重置还得走 skip-grant-tables 流程,很麻烦。
4.2 创建专用账号与授权粒度
root 只用于本地维护,应用账号应该按最小权限原则单独创建。比如给某个业务系统只开放一个库的读写权限:
-- 创建应用账号,允许从任何主机连接(内网环境常用) CREATE USER 'app_user'@'%' IDENTIFIED BY 'AppPass2025'; -- 只授予一个库的全部权限,不授予全局权限 GRANT SELECT, INSERT, UPDATE, DELETE ON bizdb.* TO 'app_user'@'%'; -- 刷新权限使立即生效 FLUSH PRIVILEGES;注意第五行FLUSH PRIVILEGES,实际上在 5.7 里创建用户和授权后不需要执行它,MySQL 会自动生效。但很多老同事的习惯是执行一遍,无害,保留也行。有个容易忽略的点:GRANT的库名如果带下划线,例如biz_db,最好用反引号括起来,否则下划线会被当成通配符,导致你授权的库范围超出预期。这个坑很隐蔽,我见过有人GRANT ALL ON biz_db.*结果biz1db也能被这个用户访问,就是下划线通配符搞的鬼。
4.3 远程连接失败:端口、bind-address 与防火墙三层检查
最常见的现象是:在数据库机器上mysql -uroot -p能登录,但从另一台机器mysql -h 192.168.x.x -uapp_user -p报Lost connection to MySQL server at 'reading initial communication packet'。这里有三层问题要查。第一,bind-address配置文件里如果写了127.0.0.1,那只能本机连,改成0.0.0.0。第二,系统防火墙或者云安全组是否放行了 3306 端口,在 CentOS 上执行systemctl status firewalld,如果开启,用firewall-cmd --add-port=3306/tcp --permanent && firewall-cmd --reload。第三,MySQL 用户表里账号的主机限制,'app_user'@'%'已经覆盖了所有 IP,但如果创建时写的是'app_user'@'192.168.1.%',那只有这一段的 IP 能连。
还有一层网络层面的问题容易被忽略:两台机器之间的连通性。先ping一下数据库机器的 IP,再telnet 192.168.x.x 3306看端口通不通。如果 ping 通但 telnet 不通,基本就是防火墙或 bind-address。本机 TCP 连接没问题但远程失败,90% 是这两者。不要一上来就改配置文件重启 MySQL,先确认端口是否实际监听在 0.0.0.0 上,用ss -lntp | grep mysqld就能看到。
4.4 常用维护命令与状态检查
部署完成不等于结束,日常维护至少要掌握五个命令。第一个是mysqladmin status,能快速看到 Uptime、Threads、Slow queries。第二个是SHOW PROCESSLIST,排查连接堆积。第三个是SHOW VARIABLES LIKE '%max_connections%',看连接上限。第四个是SHOW GLOBAL STATUS LIKE 'Threads_connected',看当前连接数。第五个是mysqladmin shutdown,优雅关闭。下面用一段常见维护命令演示:
# 查看当前实例状态 /usr/local/mysql/bin/mysqladmin -uroot -pYourStrongPass2025 status # 输出示例 # Uptime: 100 Threads: 2 Questions: 47 Slow queries: 0 Opens: 34 Flush tables: 3 Open tables: 22 Queries per second avg: 0.470如果Slow queries数字一直涨,说明有慢 SQL,后面需要打开慢查询日志定位。如果Threads_connected超过 200 且持续增长,先看应用有没有连接泄漏,不要急着调大max_connections,因为每个连接都会消耗线程栈内存,调得过大反而容易 OOM。
5. 数据目录与日志目录分离的避坑手册:离线包部署中最容易翻车的 5 个点
5.1 数据目录初始化后权限被清空
把数据目录放到独立磁盘后,目录属主必须手动设置。但有个隐藏细节:chown -R mysql:mysql /data/mysql-data执行时,如果数据目录已经初始化过,里面会有几十个文件,chown 需要遍历一遍,耗时几秒。有些同事图快只chown顶层目录,导致 mysqld 启动时报[ERROR] InnoDB: Unable to lock ./ibdata1,原因就是 mysql 用户对文件本身没有写权限。解决思路很明确:要么重新 chown -R,要么初始化前就把目录规划好、一次性给权限。
5.2 socket 文件路径不一致导致连接失败
mysqld 启动后,MySQL 客户端默认会去/tmp/mysql.sock找 socket 文件。如果你的 my.cnf 里把 socket 写到了/data/mysql-data/mysql.sock,那么客户端不带--socket参数就会报Can't connect to local MySQL server through socket '/tmp/mysql.sock'。解决方法有三种:第一,所有客户端命令都显式加--socket;第二,在 my.cnf 的[client]段里也写上同样的 socket 路径;第三,把 socket 文件软链到 /tmp 下。第三种不太推荐,因为 MySQL 重启后 socket 文件会重新创建,软链可能失效。我的习惯是统一修改/etc/my.cnf里的[client]段,这样只用维护一个配置文件。
5.3 配置文件里写错 basedir 导致启动失败
basedir写错不是立即报错,而是启动时日志里出现一堆[ERROR] Can't find messagefile: '/usr/local/mysql/share/errmsg.sys'。这个问题很迷惑,因为 MySQL 二进制明明在/usr/local/mysql/bin下,其他路径看起来也没毛病。实际上如果 my.cnf 里有basedir且路径写错,mysqld 会用它去拼接所有资源路径,包括错误消息文件。解决方法是把basedir改成绝对真实路径,或者干脆删掉basedir让 mysqld 自动推断。
5.4 初始化时报[ERROR] --initialize specified but the data directory has files in it
这是重复执行初始化时最常见的错误。5.7 的--initialize要求数据目录必须为空,但上次失败时已经生成了日志文件。我之前有同事为了省事直接删掉目录重建,结果报这个错。正确做法是rm -rf /data/mysql-data/*,不要只删表层文件,隐藏文件比如.mylogin.cnf如果存在也要删。命令行可以用find /data/mysql-data -type f -delete,但最快还是rm -rf后重建目录并 re-chown。
5.5 忘了设置lower_case_table_names=1导致表名大小写混乱
如果项目里用了不同系统之间的表结构同步,表名大小写问题会在部署后一周集中爆发。Linux 上的 MySQL 默认区分表名大小写,而 Windows 上默认不区分。如果你从别处拿到的建表脚本里有TableA和tablea混用,在 Linux 上就会偶发报错Table 'xxx' doesn't exist。这个参数必须在初始化之前写进 my.cnf,因为初始化后修改它会导致整个数据目录的表访问异常。设置方法:
[mysqld] lower_case_table_names = 1注意,如果数据目录已经初始化过,再改这个参数会导致已有的表名变成小写后找不到,最稳妥的方案是:初始化前决定好是否启用,启用就写在 my.cnf 里,再从空目录初始化。
5.6 磁盘空间满了的隐形陷阱
日志文件、binlog、undo log 都会悄悄吃掉磁盘。MySQL 5.7 默认开启 binlog 后,数据库一旦有持续写入,/data/mysql-log或 binlog 所在目录会以每小时几百 MB 的速度增长。用du -sh /data/mysql-log/*能快速看到哪个文件在膨胀。如果 binlog 堆积导致磁盘满,mysqld 会直接拒绝写入,业务报错信息是Disk full,但有时候应用侧报的是The table is full,误导你去查表结构。解决思路是设置expire_logs_days=7(5.7 里这个参数已废弃,改用binlog_expire_logs_seconds=604800),并定期用PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY清理。
6. 进阶技巧:用 mysqld 自带的初始化脚本把整个部署过程自动化
部署一台新机器时,如果还靠手工敲那十几条命令,效率太低了。我习惯把整套流程写成一个 bash 脚本,固定参数、固定目录、固定配置,交给新机器执行只需要改一个 IP。这里给出一个可直接参考的脚本骨架:
#!/bin/bash # 自动部署 MySQL 5.7.40 离线实例 # 用法:bash install_mysql.sh /data /usr/local DATA_ROOT=${1:-/data} BASE_DIR=${2:-/usr/local} MYSQL_DIR="${BASE_DIR}/mysql" DATA_DIR="${DATA_ROOT}/mysql-data" LOG_DIR="${DATA_ROOT}/mysql-log" SOCKET_FILE="${DATA_DIR}/mysql.sock" # 1. 解压与目录准备 tar -zxf mysql-5.7.40-linux-glibc2.12-x86-64.tar.gz -C "${BASE_DIR}" mv "${BASE_DIR}/mysql-5.7.40-linux-glibc2.12-x86-64" "${MYSQL_DIR}" mkdir -p "${DATA_DIR}" "${LOG_DIR}" useradd -r -s /sbin/nologin mysql 2>/dev/null chown -R mysql:mysql "${MYSQL_DIR}" "${DATA_DIR}" "${LOG_DIR}" # 2. 生成 my.cnf cat > /etc/my.cnf <<EOF [mysqld] basedir = ${MYSQL_DIR} datadir = ${DATA_DIR} socket = ${SOCKET_FILE} pid-file = ${DATA_DIR}/mysql.pid log-error = ${LOG_DIR}/error.log port = 3306 lower_case_table_names = 1 EOF # 3. 初始化 rm -rf "${DATA_DIR}"/* chown -R mysql:mysql "${DATA_DIR}" "${MYSQL_DIR}/bin/mysqld" --defaults-file=/etc/my.cnf --initialize-insecure # 4. 启动 "${MYSQL_DIR}/support-files/mysql.server" start # 5. 验证 "${MYSQL_DIR}/bin/mysql" -uroot --socket="${SOCKET_FILE}" -e "SELECT VERSION();"这个脚本的核心思想是把容易出错的路径和属主配置集中处理,避免不同机器上人为手滑。脚本里有两个值得强化的点:第一,rm -rf "${DATA_DIR}"/*前可以先检查${DATA_DIR}是不是挂载了独立磁盘,防止误删其他数据;第二,初始化后立即用SELECT VERSION();做健康检查,脚本输出版本号才代表成功,否则后续 ansible 或者 CI 流程也会基于这个结果继续。
从那次机房部署事故之后,我每次交付离线 MySQL 都会强制走一遍自动脚本,并且把.err日志路径、socket 路径、配置文件路径三件事打印在安装结束后的屏幕上。版本升级时也先在一个测试目录里全流程跑一遍再上生产。希望这篇实战拆解能帮你在内网环境里少踩几个坑。
本文还有配套的精品资源,点击获取