
简介面向仍在使用 Delphi7 维护旧项目、需要通过 dbExpress 连接 MySQL 5.7 的开发者这份资料针对网上动态库版本混杂、连接常失败的问题提供经项目实测可用的 libmysql 与 dbxopenmysql50 动态库及配套测试工程。压缩包共 17 个文件约 1.3MB包含 dll 动态库、sql 建表脚本、dpr/pas 源码、dfm 窗体、dcu 编译单元、exe 示例程序以及 docx 配置说明等便于对照查看连接配置与代码组织。已有 827 人学习下载说明其在 Delphi 旧版本数据库连接场景中具有一定参考价值。读者可获得可运行的连接示例、TSQLConnection 可视化配置说明以及判断数据库字段为空值还是空字符串的处理思路示例兼顾 Windows XP 与 Windows 10 运行环境发布时可只保留核心动态库适合需要快速排查 dbExpress 连接 MySQL 问题的开发者参考。1. 一套动态库引发的连接失败dbExpress 连 MySQL 5.7 到底缺什么接手一套 Delphi 老系统时最怕的不是业务逻辑而是「昨天还好好的」数据库连接。那套用 Delphi 写的管理端装在客户机房MySQL 服务端后来升到了 5.7程序一启动就弹 Unable to load dbxopenmysql50.dll (Error 126)重装、重启、换账号全无效。缺的其实不是配置而是两个动态库dbxopenmysql50.dll 和 libmysql.dll。dbExpress 不直连数据库它靠驱动 DLL 转发调用少一个文件或位数错一位报错都不会说出真正原因。这类环境在维护老项目、旧系统数据迁移时很常见装不好就是连不上、连上乱码、跑一阵崩溃。下面按实际装机顺序把版本选择、文件落位、驱动注册和验证一步步写清楚。2. 版本与位数对齐libmysql.dll 和 dbxopenmysql50.dll 该配哪一版动态库的坑八成不在「有没有」而在「对不对」。我见过不止一次有人从旧机器上翻出一个 libmysql.dll 直接扔进 System32程序确实不报 126 了却开始报 Client does not support authentication protocol或者连上以后中文全是问号。原因基本只有一个拿错了位数或者拿错了年代。dbExpress 的连接链路是三段式你的 EXE 加载 dbxopenmysql50.dlldbxopenmysql50.dll 再去加载 libmysql.dlllibmysql.dll 才真正和服务端说 MySQL 协议。这条链上任何一个环节的位数跟 EXE 不一致Windows 加载器就直接拒绝报出来的往往只是一句「找不到指定的模块」让人误以为是路径写错了。先把这三者的关系理顺后面所有步骤才有意义。2.1 Delphi 编译器位数决定 libmysql.dll 的位数先看工程的目标平台这一条是硬约束没有商量余地。Delphi 7 到 2007 只有 Win32 目标2010 之后才逐步引入 Win64。工程是 32 位链路上三个文件就都得是 32 位。判断一个 DLL 是 32 位还是 64 位最省事的办法是不装任何工具直接用 PowerShell 读 PE 头# 读取任意 DLL/EXE 的 PE 头输出目标架构 function Get-PEArch { param([string]$Path) $fs [IO.File]::OpenRead($Path) $br New-Object IO.BinaryReader($fs) $fs.Position 0x3C # DOS 头里 e_lfanew 的偏移 $peOffset $br.ReadInt32() # 指向 PE 签名 $fs.Position $peOffset 4 # 跳过 PE\0\0读 Machine 字段 $machine $br.ReadUInt16() $fs.Close() switch ($machine) { 0x014c { x86 (32-bit) } 0x8664 { x64 (64-bit) } default { unknown: 0x{0:X} -f $machine } } } Get-PEArch C:\App\libmysql.dll Get-PEArch C:\App\dbxopenmysql50.dll Get-PEArch C:\App\YourApp.exe这三行调用必须输出同一个结果。0x014c 是 32 位0x8664 是 64 位这是 PE 规范里定死的常量。我一般会把这三个文件放一起跑一遍肉眼对一下比事后猜错误码快得多。这一步最容易翻车的地方是 IDE 本身。你在 64 位 Windows 上装一个 32 位 DelphiIDE 跑起来是 32 位进程设计期连数据源用的是 IDE 进程加载 DLL等你编译成 64 位目标运行期又是另一套加载逻辑。所以经常出现「设计期连得上编译出来连不上」或者反过来。提示dbxopenmysql50.dll 这类老驱动基本只有 32 位发行版。如果你的工程必须是 64 位别在这条路上硬耗换官方 dbxmys 驱动或改用其他访问方式成本更低。2.2 dbxopenmysql50.dll 的版本来源与适用边界名字里的 50 指的是 MySQL 5.0 协议这个驱动出来的年代MySQL 还在用 mysql_native_password 做默认认证插件。它并不是「只支持 5.0」而是「按 5.0 的协议实现」往上兼容到 5.7 是没问题的因为 5.7 的默认认证插件仍然是 mysql_native_password。边界也很清楚它不认识 MySQL 8.0 的 caching_sha2_password。有人图省事直接把服务端升到 8.0然后回来说驱动坏了其实不是坏了是协议对不上。既然这套环境锁的是 5.7就别动服务端大版本省下来的时间够你把业务代码改两轮。另一个要确认的是导出函数名。dbExpress 驱动靠 GetDriverFunc 里配的那个入口点被调用dbxopenmysql50.dll 的导出名通常是 getSQLDriverOPENMYSQL50。不同来源的发行包偶尔会改名字配完 ini 启动报「找不到入口点」的时候先别怀疑 ini 写错了用命令看一眼导出表# 需要 Visual Studio 的开发人员命令提示符 dumpbin /exports dbxopenmysql50.dll | findstr /i getSQLDriver输出里冒号后面那一列就是真实导出名照着填进 ini 的 GetDriverFunc 即可。没有 VS 环境的话用 Dependency Walker 之类的工具看 EXPORTS 列表也一样。2.3 MySQL 5.7 服务端认证插件与客户端库的兼容窗口服务端这一侧也要对一遍不然客户端装得再对也白搭。登录 MySQL 5.7 执行-- 确认每个账号用的认证插件重点看准备给 Delphi 用的那个账号 SELECT user, host, plugin FROM mysql.user; -- 如果某个账号是别的插件改回原生密码认证 ALTER USER app_user% IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;plugin 列必须是 mysql_native_password。5.7 里绝大多数账号默认就是这个但如果这套库是从 8.0 降级下来的或者有人手动改过就可能残留 caching_sha2_password表现是客户端能连上 TCP、握手阶段被拒报错信息还特别含糊。至于 libmysql.dll 本身版本不用追新追的是「跟服务端大版本对得上、位数对得上」。我这边的常见做法是从 MySQL 5.7 对应版本的 Connector/C 包里取 libmysql.dll它和 5.7 服务端是同一套源码出来的握手行为最一致。用 5.0 时代的老 libmysql.dll 去连 5.7有时候也能连上但遇到 utf8mb4 字段、新加的数据类型就会出各种莫名其妙的问题属于典型的「今天能跑明天崩」。还有一层容易被忽略libmysql.dll 是 C 编译产物依赖对应的 VC 运行时。MySQL 5.7 时期的 Connector/C 一般依赖 VC 2013 运行时msvcr120.dll / msvcp120.dll。目标机是干净的 Server 系统时这两个运行库往往没有报错依然是 126看起来跟 libmysql.dll 缺失一模一样。分不清的时候就把 libmysql.dll 拖进 Dependency Walker看它下面挂了哪些红叉。3. 文件落位与驱动注册把两个 DLL 接进 dbExpress 的加载链版本选对只是前提接下来是「放哪儿」和「怎么让 dbExpress 认出来」。这两件事分开做出问题才好定位先保证文件能被加载再保证驱动能被注册最后才谈连接参数。3.1 DLL 存放位置与 Windows 搜索顺序Windows 加载 DLL 时按固定顺序找应用所在目录 → 系统目录System32 / SysWOW64→ Windows 目录 → 当前工作目录 → PATH 里的目录。这个顺序意味着「就近原则」——放在 EXE 同目录的优先级最高也最不容易被别的软件污染。我的做法很固定两个 DLL 一律放到 EXE 同目录绝不往 System32 里塞。理由很实际System32 是全机器共享的你今天为了 A 系统放进去一个 5.7 的 libmysql.dll明天 B 系统要 5.6 的就会互相覆盖而且这种故障极难排查因为程序目录里看着什么都没少。32 位程序在 64 位 Windows 上有个额外陷阱System32 其实是 64 位目录32 位 DLL 要放 SysWOW64。这也是为什么手动往 System32 里扔 32 位 libmysql.dll 经常「放了等于没放」。既然统一放 EXE 目录这个坑就绕过去了。目录结构大概是这个样子C:\App\ YourApp.exe dbxopenmysql50.dll libmysql.dll dbxdrivers.ini dbxconnections.ini还有一个细节如果程序是以服务方式启动的「当前工作目录」可能不是 EXE 目录而是 System32。这种情况下即便 DLL 就在身边也可能加载失败。稳妥写法是在程序启动早期显式把工作目录切过去// 程序启动时把当前目录固定到 EXE 所在路径避免服务方式启动时找不到 DLL procedure FixWorkingDir; var Buf: array[0..MAX_PATH] of Char; begin if GetModuleFileName(0, Buf, SizeOf(Buf)) 0 then SetCurrentDirectory(PChar(ExtractFilePath(Buf))); end;GetModuleFileName 传 0 取的是当前进程 EXE 的完整路径传 0 而不是 HInstance是为了在单元初始化阶段也能拿到值。SetCurrentDirectory 之后相对路径的 DLL 搜索和 ini 文件读取都会落到 EXE 目录一举两得。这段我一般放在工程文件的 begin 之前调用越早越好。3.2 dbxdrivers.ini 与 dbxconnections.ini 的段落写法dbExpress 靠这两个 ini 认驱动。dbxdrivers.ini 描述「有哪些驱动、DLL 叫什么、入口函数叫什么」dbxconnections.ini 描述「具体连哪个库、用什么账号」。两个文件都放 EXE 同目录IDE 的 bin 目录里那份不用动。; dbxdrivers.ini —— 注册一个名为 OpenMySQL50 的驱动 [Installed Drivers] OpenMySQL501 [OpenMySQL50] GetDriverFuncgetSQLDriverOPENMYSQL50 LibraryNamedbxopenmysql50.dll VendorLiblibmysql.dll BlobSize-1 ErrorResourceFile LocaleCode0000 HostName127.0.0.1 Databaseyour_db User_Nameapp_user Passwordyour_password逐项说一下值得改的GetDriverFunc 必须和 dumpbin 看到的导出名逐字一致大小写也建议照抄LibraryName 和 VendorLib 只写文件名不写路径交给搜索顺序去解决写绝对路径会让程序换台机器就废HostName 里用 127.0.0.1 而不是 localhost可以避开一部分 IPv6 解析带来的额外延迟BlobSize-1 表示按实际大小返回碰到 longtext 字段被截断的时候第一个要看的就是它。; dbxconnections.ini —— 预置一个可在设计期直接选中的连接 [MySQL57] DriverNameOpenMySQL50 HostName127.0.0.1 Databaseyour_db User_Nameapp_user Passwordyour_passwordDriverName 必须和 dbxdrivers.ini 里 [Installed Drivers] 下的键名完全一致这里写错是最常见的「驱动列表里看不到」的原因。注意密码明文写在 ini 里只适合内网调试机。正式部署时把 Password 留空登录时用代码赋值或者走加密配置。3.3 用代码显式指定驱动和连接参数ini 适合设计期快速验证运行期我建议全改成代码赋值不受 ini 文件位置影响也方便做多环境切换。var Conn: TSQLConnection; begin Conn : TSQLConnection.Create(nil); try Conn.DriverName : OpenMySQL50; // 对应 dbxdrivers.ini 里的节名 Conn.Params.Clear; Conn.Params.Add(HostName127.0.0.1); Conn.Params.Add(Databaseyour_db); Conn.Params.Add(User_Nameapp_user); Conn.Params.Add(Passwordyour_password); Conn.Params.Add(BlobSize-1); Conn.LoginPrompt : False; // 关掉登录框否则服务端跑起来会卡在弹窗 Conn.Connected : True; // 建一个查询验证链路 with TSQLQuery.Create(nil) do try SQLConnection : Conn; SQL.Text : SELECT VERSION(); Open; ShowMessage(FieldByName(VERSION()).AsString); finally Free; end; finally Conn.Free; end; end;几个参数的作用值得记一下。DriverName 是驱动注册名不是 DLL 文件名写错会报「Driver not found」。LoginPrompt 默认是 True在 GUI 程序里表现为弹框倒还好在服务或控制台程序里就是直接卡死我在部署现场踩过这个血泪经验。Connected : True 触发实际加载异常就在这里抛出把 try 放在这一行之前才能捕获到具体的错误码。如果你需要显式控制加载时机比如先判断 DLL 在不在再决定要不要连库用 LoadLibrary 试一次最直接// 用一个临时句柄试探 libmysql.dll 能否被加载失败时 GetLastError 给出精确原因 var H: THandle; Err: DWORD; begin H : LoadLibrary(libmysql.dll); if H 0 then begin Err : GetLastError; raise Exception.CreateFmt(libmysql.dll 加载失败错误码 %d, [Err]); end; FreeLibrary(H); end;这个错误码就是后面排查章节的入口126、127、193 各自对应完全不同的问题务必把码打出来不要只报一句「连不上数据库」。4. 排查清单加载失败、认证失败与中文乱码的定位路径现场排障最忌讳乱试。我习惯按加载 → 握手 → 取数三段切开每段有各自的典型错误码和报错文案对上号基本三五分钟能定位。4.1 加载类故障126 / 127 / 193 错误码怎么读现象程序启动或第一次连库就抛异常提示 Unable to load dbxopenmysql50.dll (Error 126)或者 dbExpress error: Could not load dbxopenmysql50.dll。原因126 ERROR_MOD_NOT_FOUND找不到模块127 ERROR_PROC_NOT_FOUND模块找到了但入口点找不到193 ERROR_BAD_EXE_FORMAT位数不匹配。126 最常见但它不代表文件真的不在更多时候是「文件在但它依赖的 DLL 不在」——也就是 libmysql.dll 或者 VC 运行时缺失。解决先跑 2.1 里那段 PowerShell 确认位数193 直接换文件再确认 libmysql.dll 和 dbxopenmysql50.dll 是否都在 EXE 目录最后用 Dependency Walker 打开 dbxopenmysql50.dll看它的依赖树里有没有标红的项红的那个就是要补的运行时。现象换成 64 位编译后报 Error 193 或者「不是有效的 Win32 应用程序」。原因dbxopenmysql50.dll 是 32 位驱动64 位进程加载不了。解决要么把工程改回 Win32 目标要么放弃这套驱动改走官方 dbxmys。别试图找 64 位版本的 dbxopenmysql50.dll基本找不到。4.2 连接类故障握手阶段的报错定位现象DLL 加载正常连库时报 Client does not support authentication protocol requested by server。原因服务端账号用的是 caching_sha2_password 或其他非原生插件老 libmysql.dll 不认识。常见于库是从 8.0 降级过来、或者建账号时手滑指定了插件。解决按 2.3 里的 SQL 查 plugin 列改回 mysql_native_password 后 FLUSH PRIVILEGES重启程序再试。改完记得用同一个账号在命令行先连一次确认服务端侧是通的。现象报 Cant connect to MySQL server on 127.0.0.1 (10061)。原因这个跟驱动没关系纯粹是网络层没通。要么 MySQL 服务没起要么 bind-address 只监听 127.0.0.1 而你在别的机器上连要么防火墙拦了 3306。解决目标机上 telnet 127.0.0.1 3306 试一下端口通不通再看 my.ini 里的 bind-address。这属于网络排查不要往 DLL 上想。4.3 数据类故障字符集与字段截断现象连接成功后中文字段全变成问号或者变成一堆乱码。原因客户端和服务端的字符集没对上。libmysql.dll 默认按 latin1 建连接服务端表是 utf8mb4中间就错位了。解决优先在服务端把库和表的字符集改成 utf8mb4然后确认连接建立后执行一次 SET NAMES utf8mb4。老版本 libmysql.dll 对 utf8mb4 支持不完全时只能退回 utf8代价是存不了四字节字符比如部分表情符号这个取舍要提前跟业务方说清楚。现象查询长文本字段取到的内容总是被截断在一半。原因BlobSize 参数没配或者配小了dbExpress 默认的 blob 缓冲装不下长文本。解决连接参数里显式加 BlobSize-1让它按实际长度返回。这个参数在 ini 和代码里都要写两处不一致时以代码里的 Params 为准。5. 装完怎么验三条最小验证路径装完不验证等于没装。我的习惯是分三层跑从下往上任何一层不通过就停在那儿不要跳着测。第一层验加载只看 DLL 能不能被进程吃进去。写个三行的控制台程序LoadLibrary 两个文件打印返回值和 GetLastError。这一步通过说明位数、依赖、路径全对后面再出问题就不用往这上面想了。第二层验协议用 libmysql.dll 自己的版本函数确认它真的在工作// 直接从 libmysql.dll 取客户端版本绕过 dbExpress确认底层库可用 function MySQLClientVersion: string; var H: THandle; Fn: function(): PAnsiChar; cdecl; begin Result : (not loaded); H : LoadLibrary(libmysql.dll); if H 0 then Exit; try Fn : GetProcAddress(H, mysql_get_client_info); if Assigned(Fn) then Result : string(Fn()); finally FreeLibrary(H); end; end;这里用 cdecl 是因为 libmysql 是 C 接口调用约定必须对上写成 stdcall 会直接把栈搞乱表现为调用完程序莫名其妙崩掉。返回值形如 5.7.x跟服务端的 SELECT VERSION() 对一下大版本号差太远就换库。第三层验业务跑一条真正带中文和长文本的查询。我一般直接拿业务表里最容易出问题的那张SELECT 一条含中文的、一条超过 64KB 的看是不是完整取回来。这一步过了才敢交付。验证层检查对象通过标准失败时优先看加载层dbxopenmysql50.dll、libmysql.dllLoadLibrary 返回非 0位数、VC 运行时、目录协议层libmysql.dll版本号与服务端大版本一致取错文件、System32 残留旧版业务层TSQLConnection 实际查询中文正常、长文本完整BlobSize、SET NAMES三层都过之后还有个小技巧把整个过程在一台干净的测试机上重放一遍。开发机上往往装着各种运行库和旧版 DLL很多问题会被掩盖干净机器上暴露出来的才是客户机房会遇到的。我吃过一次亏开发机连得好好的装到现场就是 126最后发现是少了 VC 2013 运行时。从那以后我每次交付前都强制走一遍干净机验证两个 DLL、两个 ini、一个运行时清单缺一样都不算装完。希望帮到你。本文还有配套的精品资源点击获取