
简介这是一份 MySQL 4.1.11 的 .tar.gz 源码包面向需要在 Linux/Unix 环境编译旧版数据库、排查遗留系统或研究数据库早期实现的技术人员。作为 4.x 分支的代表性发布包体完整收录服务器、客户端及配套工具的源码与构建脚本。包内共有 4541 个文件不仅包含 829 个 C 文件、441 个头文件、351 个 C 文件与 191 个 cc 文件还收集了 327 个测试结果、326 个测试脚本、236 个 Tcl 脚本以及大量 automake 配置、Java 代码和 shell 工具构成从源码、构建系统到回归测试的完整工程目录压缩包整体约 21.82MB已有 197 人学习。借助该包可还原 MySQL 4.x 的存储引擎、复制协议与优化器代码也能通过 configure、make、make install 的典型流程理解开源软件从源码到可运行服务的编译安装链路。无论是维护遗留系统、排查旧环境兼容问题还是想对照现代版本梳理数据库核心模块演进这份资料都提供了直接可用的一手代码和脚本素材。1. 快二十年的源码包mysql-4.1.11.tar.gz 现在到底还能拿来干什么mysql-4.1.11.tar.gz 这个名字对今天的数据库从业者来说已经相当陌生。MySQL 4.1 系列是整个数据库走向「每字段独立字符集、子查询、预处理语句」的关键一代而 4.1.11 是那个系列的中期修订版。你现在会遇到这个包大概率不是想考古而是手里确实攥着一个没法扔的场景某台旧服务器的业务库还压在这套版本上或者交接资料里躺着一个没人敢动的源码包领导只丢给你一句「看能不能把数据弄出来」。这篇文章不打算把 4.1.11 讲成博物馆展品。它要解决的是三类实际问题在老机器上把 4.1.11 重新编译跑起来、把历史数据干净地迁到新版、以及搞清楚这套老代码在今天的 Linux 上为什么要跟你对着干。适合的读者是接手旧系统的一线运维和开发以及需要用老版本做兼容性验证的人。先立一个结论4.1.11 在现代环境里能编译、能启动、能导数据但每一步都要按老规矩来你越熟悉 5.x 之后的新习惯踩的坑反而越多。2. 编译前先给 4.1 老树把脉工具链与三项关键检查2.1 为什么 4.1 源码包在今天编译会翻车三条代际差异MySQL 4.1 的代码是二十年前的工具链环境下写出来的今天的编译器和系统库跟它之间隔着三代变化。第一道坎是编译器语法。4.1 的源码里有大量老式 C 写法部分汇编代码段也是按当时 binutils 的语法写的。新版 gcc 默认开了更严格的告警和更激进的优化很多当年只是 warning 的代码现在直接升级成 error 中断编译最典型的是-fno-strict-aliasing这类优化开关与老代码的冲突。第二道坎是系统库拆分。老版本 MySQL 依赖的不少函数当年直接由 libc 提供后来这些函数被拆到独立的库里。最常见的两个crypt()被拆到 libcrypt某些老的多线程接口在不同 glibc 版本上签名也有变化。表现就是 configure 检查项失败或者 make 链接阶段报 undefined reference。第三道坎是安全组件。4.1 的 SSL 支持绑定的还是 OpenSSL 0.9.x 时代的 API新版 OpenSSL 把大量老函数废弃甚至直接移除。如果你不加选择地打开--with-openssl编译到 SSL 相关文件时几乎必挂。所以我在编译老版本时有一条原则默认不启用 SSL能用 socket 本地访问的就别折腾 TLS。这不是偷懒是让 4.1 老老实实跑起来的最短路径。2.2 环境检查一条命令摸清 gcc、make、bison、ncurses 与 OpenSSL动手 configure 之前先把工具链摸一遍。用下面这组命令检查五个关键项任何一个缺失或不兼容都能提前预判而不是等编译跑到一半才翻车echo --- 编译器 ---; gcc --version 2/dev/null | head -1 echo --- make ---; make --version 2/dev/null | head -1 echo --- bison ---; bison --version 2/dev/null | head -1 echo --- ncurses ---; pkg-config --exists ncurses 2/dev/null pkg-config --modversion ncurses echo --- openssl ---; openssl version 2/dev/nullgcc 和 make 是必须存在的这不用多说。bison 这个要单独讲4.1 源码包里其实已经带好了由 bison 生成的sql_yacc.cc和sql_lex.cc理论上不装 bison 也能编。但 configure 脚本里仍然会检查 bison 是否存在找不到就报错退出。省事的办法是装上但注意版本别太新bison 3.x 处理老式 yacc 语法偶尔会出问题有条件就装 2.x。ncurses 是另一个硬依赖老版本 MySQL 的终端交互和密码输入依赖 curses 库缺了它 configure 会卡在 termcap 检查项上。OpenSSL 这里要反过来看如果系统里没有装开发头文件反而是好事这能帮你杜绝误开 SSL 编译的念头。如果装了也不要主动去配置--with-openssl。我见过太多人在这一项上浪费时间最后发现业务场景根本不走 TLS。2.3 configure 老式选项与现代习惯的差异prefix 与引擎MySQL 4.1 的 configure 是 autoconf 老风格跟 5.7 之后的 CMake 完全是两个物种。它没有-DWITH_XXX这套写法全部是--with-xxx和--enable-xxx。而且 4.1 的默认安装路径是/usr/local/mysql默认数据目录是编译前缀下的var而不是data这一点和 5.x 之后完全不一样也是最容易埋坑的地方。另一个容易忽略的是存储引擎。4.1 时代 MyISAM 是绝对主力InnoDB 虽然已经集成进标准源码树但源码包里自行编译时多个发行版的历史经验都建议在 configure 阶段显式确认 InnoDB 是否启用。如果你拿到的是一个裁剪过的二次打包源码没准 InnoDB 根本没编进去。我一般会在 configure 命令里显式带上--with-innodb如果手头这个小版本的 configure 不认识这个选项说明它默认已内置忽略即可。这样两种场景都能兜住。配置前缀时还有个习惯值得坚持不要装到系统默认目录单独指定一个业务目录比如/opt/mysql-4.1.11。老版本卸载本来就不干净装到独立目录将来整个目录一删就完事数据目录在它底下也方便打包迁移。3. 把 ./configure 到 make install 跑通最小命令与必调参数3.1 configure 最小可用命令禁 SSL、定 charset、选引擎进入正题。假设你已经把 mysql-4.1.11.tar.gz 解压到了/opt/src/mysql-4.1.11下面这条命令是我在 64 位 Linux 上编译老版本时最常用的配置组合cd /opt/src/mysql-4.1.11 ./configure \ --prefix/opt/mysql-4.1.11 \ --with-mysqld-usermysql \ --with-charsetutf8 \ --with-collationutf8_general_ci \ --with-innodb \ --disable-assembler逐个说参数。--prefix指定安装根目录后续所有二进制、库文件、man 文档都会装到这里。--with-mysqld-usermysql让 mysqld 在启动时自动 setuid 到 mysql 用户避免用 root 跑数据库进程这是底线。--with-charsetutf8和--with-collationutf8_general_ci是 4.1 时代设置默认字符集的方式注意 4.1 里的 utf8 是早期实现不等于后来 5.5 引入的 utf8mb4但作为老库的默认字符集utf8 总比默认的 latin1 实用。--with-innodb上面说过是给「InnoDB 没默认编进去」的源码包兜底用的。最值得注意的是--disable-assembler。4.1 源码里有一段针对 x86 的汇编优化代码当年能提升性能但在新版本 binutils 上经常因为指令写法过时导致编译失败。在 64 位系统上这段汇编本身就没什么收益直接关掉最干净。这里我刻意没有加任何--with-openssl相关参数。老版本 MySQL 默认不会强制链接 OpenSSL你不主动开启它就能绕开新版 OpenSSL API 不兼容的坑。如果某些小版本 configure 默认探测到了系统里的 OpenSSL你可以显式加--without-openssl再试一次个别版本选项名略有出入报错不认识的话直接忽略即可。3.2 make 与 make install链接期报错的两个兜底方案configure 顺利结束后进入编译阶段。这里有一个和现代项目很不一样的地方建议第一次不要开并行编译老老实实跑默认串行 make。4.1 的 Makefile 并行处理能力远不如当代构建系统手动加-j4容易触发莫名其妙的头文件依赖竞态报出来的错误会让你误判是代码问题还是编译环境问题。make第一次编译如果顺利通过后续再想重编可以开make -j2。这个过程在普通服务器上大约需要十几分钟到半小时取决于机器性能。如果中途报错绝大多数集中在两个地方。第一个是链接阶段报undefined reference to crypt。原因是新版系统把 crypt 函数从 libc 挪到了独立的 libcrypt 库。处理方式是重新 configure在环境变量里补上链接库export LIBS-lcrypt ./configure \ --prefix/opt/mysql-4.1.11 \ --with-mysqld-usermysql \ --with-charsetutf8 \ --with-collationutf8_general_ci \ --with-innodb \ --disable-assembler make clean make注意LIBS环境变量必须写在 configure 之前同时要make clean清掉之前一半的编译产物否则残留的 .o 文件会让你白等一轮。第二个常见中断点是汇编文件报错。如果你没有加--disable-assembler又刚好在 64 位系统上编译可能会看到形如Error: suffix or operands invalid for movq之类的提示这是老汇编语法和 binutils 新语法的冲突。解决方案就是回 configure 阶段补上--disable-assembler然后同样make clean重来。编译通过后执行make install安装本身基本不会出问题。4. 初始化与首启老版本的数据目录在 var 不在 data4.1 建用户、搭目录、跑 mysql_install_db安装完成后别急着启动。4.1 没有 5.7 之后的--initialize初始化数据目录靠的是一个独立脚本mysql_install_db。在执行前先要把系统用户和目录结构准备好这是老版本最容易忽略的一步groupadd mysql useradd -g mysql -s /sbin/nologin mysql mkdir -p /opt/mysql-4.1.11/var chown -R mysql:mysql /opt/mysql-4.1.11 /opt/mysql-4.1.11/bin/mysql_install_db --datadir/opt/mysql-4.1.11/var --usermysqlmysql_install_db这个脚本在源码树里的位置是scripts/mysql_install_db安装后位于bin/mysql_install_db直接用安装后的路径即可。--datadir指定数据目录4.1 的习惯是放在安装前缀下的var目录不是 5.x 常用的data。--usermysql让初始化脚本以 mysql 用户身份创建系统库和权限表避免后面 mysqld 因目录属主不对而拒绝启动。需要说明的是mysql_install_db创建的是mysql系统库里面包含user、db、host等权限表以及test测试库。初始化完成后root 账号默认没有密码只能通过本地 socket 连接这是老版本的安全边界后面要自己补上密码策略。4.2 my.cnf 配置字符集、socket、引擎开关初始化完成后写一份最小可用的 my.cnf。老版本对配置项的容忍度和新版本不一样写多了反而容易触发不识别参数导致启动失败。有些参数在 5.7 里还能用在 4.1 里直接就报错退出所以配置文件要尽量克制[mysqld] user mysql basedir /opt/mysql-4.1.11 datadir /opt/mysql-4.1.11/var socket /opt/mysql-4.1.11/var/mysql.sock port 3306 default-character-set utf8 skip-locking [client] socket /opt/mysql-4.1.11/var/mysql.sock default-character-set utf8这里有两个 4.1 特有的关键点。第一是default-character-set在 4.1 里它是 mysqld 的合法参数作用是设定服务端默认字符集这个参数在 5.0 之后被改名成了character-set-server你要是拿新习惯给 4.1 写character-set-serverutf8mysqld 会直接拒绝启动。第二是skip-locking它关闭外部文件锁。老版本的外部锁在 NFS 和某些现代文件系统上会引发诡异的表损坏问题直接关掉最省心。[client]段里的socket必须和[mysqld]段一致。前面说过 4.1 默认把 socket 放在 datadir 下而客户端默认找的是/tmp/mysql.sock不一致就会出现 2002 连接错误。在配置文件里统一指定是最稳妥的做法比每次命令行传-S参数要可靠。4.3 mysqld_safe 启动、看日志、跑通首次自检启动 4.1 的服务端标准入口是mysqld_safe它会负责拉起 mysqld 进程并在 crash 后尝试重启。启动命令就这么简单/opt/mysql-4.1.11/bin/mysqld_safe --defaults-file/opt/mysql-4.1.11/my.cnf 启动之后别急着连先确认进程真的活下来了。老版本没有 systemd 托管也没有现成的 status 命令我一般用两步自检sleep 2 /opt/mysql-4.1.11/bin/mysqladmin -uroot ping /opt/mysql-4.1.11/bin/mysql -uroot -e SELECT VERSION(); SHOW VARIABLES LIKE character_set%;mysqladmin ping能通说明服务端已经响应请求。第二条命令验证版本号和字符集实际生效值。如果 ping 不通第一步永远是看错误日志/opt/mysql-4.1.11/var/目录下的*.err文件老版本把几乎所有启动失败的原因都写在里面。很多新手习惯先翻系统日志但 4.1 时代很多发行版根本没有把 mysqld 的输出接到系统日志还是直接看 err 文件最靠谱。5. 避坑老版本在当代内核上运行的五条排查记录5.1 现象configure 卡在 termcap / bison 检查项configure 输出里出现checking for termcap functions library... configure: error: No curses/termcap library found这是缺 ncurses 开发包。原因很简单新版发行版默认不装 ncurses-devel而 4.1 的 configure 又是老式探测逻辑不会自动适配 pkg-config。解决方法是安装对应开发包然后把头文件路径显式指给 configureexport C_INCLUDE_PATH/usr/include/ncursesw export LIBS-lncursesw ./configure ...如果系统里只有 ncursesw带宽字符支持上面的路径调整就能让 configure 认出来。bison 报缺的话装一个 bison 2.x 的版本即可没有 bison 3.x 环境时也不需要单独编译。5.2 现象链接阶段报 undefined reference to cryptmake跑到最后链接 mysqld 时报undefined reference to crypt。这是因为新版系统的 crypt 函数从 libc 拆到了 libcrypt而 4.1 的链接参数里只有-lc。解决办法就是前面提过的export LIBS-lcrypt再重配。注意这个坑只出现在某些较新的发行版上老系统本身不会有。判断方法很简单在有问题的系统上执行grep -l crypt /usr/lib/libc.*如果找不到符号基本就是这个原因。5.3 现象mysqld 启动即退出报打不开特权表错误日志里出现Couldnt find table或者Cant open and lock privilege tables: Table mysql.user doesnt exist这是典型的没初始化数据目录或者 mysqld 读到的 datadir 是空的。另一种情况是 datadir 路径配置正确但目录属主不是 mysqlmysqld 没有权限写文件。解决方法是回头执行 4.1 小节的mysql_install_db并确认chown -R mysql:mysql覆盖到了整个安装目录和数据目录。启动验证时用ls -la /opt/mysql-4.1.11/var看一眼mysql目录和test目录存在且属主为 mysql才是正常状态。5.4 现象客户端连接报 2002找不到 socketmysql -uroot报ERROR 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock。原因不是服务端没起来而是 mysqld 把 socket 建到了 my.cnf 指定的/opt/mysql-4.1.11/var/mysql.sock客户端却按默认路径/tmp/mysql.sock去找。解决方式有两种命令行加-S /opt/mysql-4.1.11/var/mysql.sock或者像我一样在 my.cnf 的[client]段里固定 socket 路径。这个问题在新版本里不常见因为新版客户端和服务端默认路径基本一致但 4.1 年代源码包安装的默认路径就不是 /tmp所以几乎每个人都会撞一次。5.5 现象字符集乱码SET NAMES 也救不回来数据写入时正常SELECT 出来是问号或乱码执行SET NAMES utf8后部分表变正常、部分表还是乱。原因是 4.1 的字符集是分层的服务端默认字符集、客户端连接字符集、每个字段自己的字符集三层可以各自独立。如果表在建表时字段指定了 latin1连接用 utf8那查询时会发生双向转换而转换规则遇到特殊字节就会变成乱码。排查时先看SHOW CREATE TABLE确认字段的 charset 到底是谁然后让客户端连接字符集和字段字符集保持一致不要跨字符集硬来。导出数据时同样按源表的实际字符集来迁移到新版后再统一转成 utf8mb4 也不迟。6. 把数据从 4.1 里安全搬走mysqldump 导出与导入新版的最小流程6.1 导出命令固定字符集与版本注释对绝大多数人来说让 4.1.11 跑起来不是终点把里面的业务数据救出来才是。导出用 mysqldump命令如下/opt/mysql-4.1.11/bin/mysqldump \ -uroot \ --all-databases \ --default-character-setutf8 \ --quick \ --add-drop-table \ mysql-4.1.11-dump.sql--default-character-setutf8让导出客户端以 utf8 作为连接字符集避免在导出过程中发生转码。--quick是逐行读取而不是缓存到内存老库数据量大时能明显降低内存占用。--add-drop-table在每张表前生成 DROP TABLE 语句导入时不用手动清理旧表。--all-databases会连带 mysql 系统库一起导出但老版本权限表结构和新版完全不同所以我实际迁移时通常不迁 mysql 库而是只导出业务库权限账号到新库重建。注意这里不要加--single-transaction它只在 InnoDB 表上有意义而 4.1 的数据大概率以 MyISAM 为主。导出文件开头几行会看到一堆/*!40101 SET ... */这是 MySQL 的版本条件注释。以40101开头的注释表示「客户端版本大于等于 4.1.1 时执行里面的语句」所以这份文件在高版本客户端上导入时会自动执行这些设置语句这是 4.1 时代留下的跨版本兼容设计不要觉得它们碍事。6.2 新版导入的兼容点引擎、字符集与权限表导入前先检查引擎。在 4.1 端执行SHOW TABLE STATUS FROM 你的库名;看每张表的 Engine 列。如果只有 MyISAM 和 InnoDB导入新版基本没障碍。如果出现 BDB 或其他老引擎新版可能已经移除支持需要提前把这些表转成 MyISAM 或 InnoDB。mysql -uroot -p mysql-4.1.11-dump.sql导入本身就是一个重定向没有太多参数。真正要注意的是导入后的验证。新版导入 utf8 数据时8.0 会默认把 utf8 当 utf8mb3能正常导入但可能产生告警不影响数据内容。latin1 表导入 utf8mb4 目标库时要确认连接字符集否则原本正常的字节会被当作错误的编码重新解释一次。我的习惯是导入前在 4.1 端记录各业务表的行数导入后在新端重新执行SELECT COUNT(*)对比一致才收工。6.3 收尾习惯双向 dump 验证法与一条土办法验证数据完整性我常用一个土办法把导入新库的数据再反向 dump 一次导入一台测试用的 4.1 实例两边行数对上才算数据真正无损。这不是信任问题而是 4.1 到新版之间隔了太多大版本任何一次字符集或引擎转换的小偏差行数对不上时一眼就能看出来。具体流程是# 新端反向导出 mysqldump -uroot -p --all-databases --skip-lock-tables verify-dump.sql # 导入测试用 4.1 实例 /opt/mysql-4.1.11/bin/mysql -uroot verify-dump.sql # 两端执行同样的行数统计逐表对比对照表按下面三种情况判结果MyISAM 表行数一致通过InnoDB 表行数一致但表空间文件大小明显异常需要继续检查是否发生了索引重建字符集列出现乱码回源头查导出的 charset 与表字段是否匹配。4.1 没有 information_schema统计行数只能在命令行逐条 count。我自己的收尾习惯是导出文件永远保留两份一份原样归档一份作为导入源绝不直接用原文件反复测试。老版本数据库的备份恢复本身就玄学成分偏多多留一份原样文件就是给自己留后悔药。这个方向值不值得投入我的判断很简单只要还有业务数据压在这个版本上把 4.1 的实例干净地拉起来并导出数据就是成本最低的一条迁移路径。希望帮到你。本文还有配套的精品资源点击获取