
最近在给一个模拟项目做数据库模块改造Windows 客户端需要直连内网 MySQL本来以为 Qt 自带的 SQL 模块已经是开箱即用结果程序一跑控制台直接给我来一句“QSqlDatabase: QMYSQL driver not loaded”。查了一圈才发现Qt 官方安装包里根本不会顺手提供 MySQL 驱动插件SQLite 是白送的MySQL 得靠自己编译。这篇文章就把我用 Qt 编译 MySQL 驱动的全过程写下来包括版本匹配、CMake 配置、qmake 老办法、Windows 和 Linux 下的部署坑以及最后怎么验证驱动真的能用。如果你也踩过“驱动加载失败”这个坑或者准备做 Qt 和 MySQL 的跨平台联调这篇应该能帮你少走不少弯路。1. 为什么 Qt 不直接给我们一个现成的 MySQL 驱动很多新手拿到 Qt 后第一反应是打开示例代码直接写QSqlDatabase::addDatabase(QMYSQL)然后期待一切顺利。实际上这条路从源头就堵住了一部分因为 Qt 官方二进制安装包里数据库插件默认只编译了 SQLite。1.1 官方安装包到底缺了什么Qt 的在线安装器在 Windows 上默认带了一堆插件比如样式插件、平台插件、图像格式插件但sqldrivers目录下往往只有qsqlite.dll。这不是 Qt 偷懒而是 MySQL 驱动属于“依赖第三方客户端库”的插件Qt 官方不能在你的机器上凭空知道 MySQL 客户端库放在哪里更没法替你决定这个驱动是配合 MySQL 8.0 还是 MariaDB 编译。我在那个模拟项目最开始也天真过既然 Qt 支持 MySQL那直接把安装目录翻一遍找到某个qsqlmysql.dll复制过去不就行了实际上 Qt SDK 的plugins\sqldrivers里只有 SQLiteMySQL 相关的一律没有。你要想拿到带 MySQL 的驱动唯一的正路是自己拿到 Qt 的 SQL 模块源码在本地用完全一致的编译器把它编出来。1.2 驱动不是一个普通 dll它取决于编译器这里要说一个关键点qsqlmysql.dll不是一个大而全的 MySQL 客户端它其实是一个 Qt 插件外壳里面动态链接了两个东西一是 Qt 自身的 SQL 驱动框架二是 MySQL 的客户端库libmysql.dll。这意味着驱动必须同时匹配你的 Qt 版本和 MySQL 客户端库的位数与运行时。如果你用 MSVC 2019 编译器装的 Qt那编译出来的插件只能被对应 Qt 版本调用如果你用的 Qt 是 MinGW 版本那插件也要跟着用 MinGW 去编。混着用经常会出现“插件加载了但内部符号对不上”的诡异报错。一句话总结编译 MySQL 驱动的本质就是把 Qt 的 SQL 框架和 MySQL 客户端库用同一套工具链“缝”在一起。1.3 编译前必须先想清楚的事动手之前请先回答这几个问题目标机器的 Qt 是 MSVC 套件还是 MinGW 套件MySQL 服务器是 8.0 还是 5.7客户端库准备用官方 Connector/C还是系统自带的 libmysqlclient程序最终是动态链数据库驱动还是打算静态编译进 exe这些问题直接决定你后面下载哪个源码分支、CMake 参数填什么、复制 dll 复制到哪里。我在一开始就是因为没确认编译器导致第一次编出来的插件在 Qt Creator 里怎么都加载不出来后面才追到是工具链不一致。2. 编译前准备清单版本、环境、目录三件事如果把这篇文章压缩成一句话那就是“先对齐版本再动手编译”。版本对不上后面所有步骤都是白费。2.1 三个版本要同时对上第一个是 Qt 版本第二个是 MySQL 客户端库第三个是编译器。三者不是独立存在而是互相约束的关系维度需要对齐的内容对不齐的后果Qt 版本插件和 Qt 库版本必须一致插件加载失败提示版本不匹配MySQL 客户端库驱动编译时链接的 libmysql 与运行时加载的 dll 必须一致加载后报找不到入口点编译器/套件MSVC 和 MinGW 不能混用链接报错或者生成的插件完全无法加载位数32 位与 64 位必须一致Windows 下直接加载失败协议版本MySQL 客户端库支持服务器认证方式连接时提示认证插件无法加载以我自己为例机器上是 Qt 6.5.3 MSVC 2019 64 位套件数据库是 MySQL 8.0所以我下载的 MySQL Connector/C 也是 64 位版本头文件路径和库文件路径都指向同一个目录。如果你用的是 Qt 5.15那源码分支就要切到v5.15.2这种对应 tag千万不能拿 Qt 6 的源码硬编。2.2 源码哪儿来qtsql 模块不需要整个 Qt这一步是很多教程没有讲清楚的。你不必去下载几个 GB 的完整 Qt 源码包只需要 Qt 的qtsql模块源码即可因为QSqlDatabase、QSqlDriver以及所有数据库插件都在这个模块里。最常见的方式是从官方 Git 仓库克隆对应分支git clone --depth 1 --branch v6.5.3 https://github.com/qt/qtsql.git如果你没有 git也可以从官网下载源码压缩包只要里面包含src/plugins/sqldrivers目录就行。这个目录才是真正的驱动插件源码。有一点要提醒qtsql 模块构建时依赖已经安装好的 Qt 基础库。也就是说如果你机器上已经通过在线安装器装了 Qt 6.5.3那就直接用这个环境作为CMAKE_PREFIX_PATH不需要再编译整个 Qt。2.3 MySQL 客户端库的准备Windows 上推荐直接下载 MySQL Connector/C 的 zip 包解压后目录里会有include和lib两个文件夹其中lib下会看到libmysql.lib和libmysql.dll。选择 64 位版本时要注意文件名后缀MSVC 使用的导入库是libmysql.lib运行时动态库是libmysql.dllMinGW 环境下可能还需要把libmysql.lib转换成libmysql.a或者直接找 MinGW 可用的版本我在实际准备时把 Connector/C 解压到了D:\deps\mysql-connector-c-8.0然后把路径记下来。后面 CMake 配置时MySQL_INCLUDE_DIR指到 include 目录MySQL_LIBRARY指到 lib 目录下的导入库文件。Linux 下一般是用包管理器装客户端库sudo apt install libmysqlclient-dev装完后头文件一般在/usr/include/mysql库文件在/usr/lib/x86_64-linux-gnu/libmysqlclient.so比 Windows 省心很多。3. 正式编译CMake 流程实测记录我从 Qt 6.2 开始改用 CMake 构建 SQL 驱动整体思路很直接先配置 qtsql 模块让它知道 Qt 装在哪里、MySQL 头文件和库文件在哪里然后构建并安装。下面是我整理出的完整流程。3.1 Qt 6 里的 CMake 方式假设你的 Qt 安装在D:\Qt\6.5.3\msvc2019_64MySQL Connector/C 解压在D:\deps\mysql-connector-c-8.0qtsql 源码放在D:\src\qtsql那么可以这样配置cmake -S D:/src/qtsql -B D:/src/qtsql-build -G Ninja ^ -DCMAKE_PREFIX_PATHD:/Qt/6.5.3/msvc2019_64 ^ -DCMAKE_BUILD_TYPERelease ^ -DCMAKE_INSTALL_PREFIXD:/Qt/6.5.3/msvc2019_64 ^ -DMySQL_INCLUDE_DIRD:/deps/mysql-connector-c-8.0/include ^ -DMySQL_LIBRARYD:/deps/mysql-connector-c-8.0/lib/libmysql.lib需要注意CMAKE_PREFIX_PATH要指到 Qt 库所在的那个目录也就是包含lib/cmake/Qt6的一层。CMAKE_INSTALL_PREFIX最好也指到同一个目录这样插件会被直接装进 Qt 的plugins/sqldrivers下面。配置完成后开始构建和安装cmake --build D:/src/qtsql-build --config Release --parallel cmake --install D:/src/qtsql-build整个编译过程其实很快因为只编 qtsql 模块加数据库驱动插件不会重新编译整个 Qt。第一次配置时如果报错多半是MySQL_LIBRARY路径写错或者套件配置不对。3.2 怎么判断 CMake 是否真的看到了 MySQL很多时候命令执行完控制台也会出现“MySQL support goes on”的提示。如果你配置完不确定到底有没有启用 MySQL 驱动可以直接去构建目录下找生成的插件文件D:/src/qtsql-build/plugins/sqldrivers/qsqlmysql.dll如果这个文件存在说明驱动已经编出来了。如果不存在多半是 CMake 在配置阶段没有找到 MySQL 头文件或库于是自动跳过了 MySQL 插件。这种情况去检查CMakeCache.txt里的MySQL_INCLUDE_DIR、MySQL_LIBRARY两个变量看值是否被正确设置。我还踩过一个细节把MySQL_LIBRARY指成了libmysql.dll而不是libmysql.lib。CMake 不一定报错但链接阶段会失败。所以 Windows 下导入库.lib和目标 DLL 要分清楚CMake 配置填的是 .lib运行时才需要 .dll。3.3 老项目的另一条路Qt 5 时代的 qmake虽然现在标配是 CMake但公司里还有不少老项目停在 Qt 5.15尤其是之前用 Qt Creator 的 qmake 构建的系统。Qt 5 的 MySQL 驱动编译传统做法是进到 Qt 源码的 sqldrivers 目录用 qmake 带上 MySQL 目录参数生成 Makefile。假设我的 Qt 5.15.2 源码在C:\Qt\5.15.2\Src\qtbase\src\plugins\sqldrivers那么执行cd C:\Qt\5.15.2\Src\qtbase\src\plugins\sqldrivers qmake -- MYSQL_INCDIRC:\mysql-connector\include MYSQL_LIBDIRC:\mysql-connector\lib nmake如果是 Windows 上用 MinGW 的 Qt生成 Makefile 后要执行mingw32-make不是nmake。编完之后同样会在plugins/sqldrivers下生成qsqlmysql.dll手动复制到 Qt 安装目录的对应位置即可。给还在维护 Qt 5 项目的朋友提个醒qmake --后面那两个变量名一定要写成大写MYSQL_INCDIR和MYSQL_LIBDIR小写是不认的。这也是我帮同事排查半天才发现的低级错误。4. Windows 下的那些坑MSVC、MinGW 与 libmysql.dllWindows 是 Qt 主要阵地但也是坑最多的地方。最典型的场景是插件编译出来了也复制到 Qt 的 plugins/sqldrivers 里了但程序运行后依然提示驱动没加载。4.1 复制插件的正确位置和路径Qt 找 SQL 驱动插件不是漫无目的地找它只会去固定的几个目录查找。以 Qt 6.5.3 MSVC 2019 64 位为例插件最终要放到D:\Qt\6.5.3\msvc2019_64\plugins\sqldrivers\qsqlmysql.dll如果你用 Qt Creator 开发工程运行时使用的 Qt 库路径取决于你会话里选的是哪个 Kit。很多人编完插件后随手复制到了某个 Qt 安装目录但 Qt Creator 当前用的是另一个 Qt 版本或套件导致插件永远加载不到。我的做法是直接把CMAKE_INSTALL_PREFIX指向 Qt 安装目录让 CMake 安装时自己落到正确位置避免后续手动复制出错。4.2 MSVC 套件与 MinGW 套件的差异MSVC 套件编译出来的插件依赖的是 Microsoft C 运行时和 Qt 的 MSVC 库MinGW 套件编译出来的插件依赖的是 MinGW 运行时。这两个体系不互通哪怕版本完全一致混用也可能直接加载失败。如果你在 Windows 上用的是 Qt 官方“MinGW 11.2.0 64-bit”套件那 MySQL 客户端库也得是 MinGW 能链接的库。MSVC 的libmysql.lib直接让 MinGW 的 g 去链接经常会出现“File format not recognized”的错误。所以最好直接用 MSVC 套件配 MSVC 编译或改用 MySQL 提供的源码或 MinGW 兼容库自行生成。我后来换了思路既然服务器程序在 Linux 上跑Windows 客户端用 MSVC 套件那么在 Windows 环境上就固定用 MSVClibmysql.lib 组合不再折腾 MinGW。这样一条路走到底反而最省事。4.3 打包到客户机器经常漏掉的东西插件驱动编好只是第一步发布程序时还要带上 Qt 的插件目录结构并且额外带上 MySQL 客户端库。这里有一个非常容易漏的部分libmysql.dll必须在客户机器上可用。windeployqt工具能帮你自动收集 Qt 相关的 dll但通常不会收集第三方 MySQL 库。所以我在发布脚本中手动加了这么一句xcopy /Y D:\deps\mysql-connector-c-8.0\lib\libmysql.dll .把这个 dll 放到和 exe 同级目录或者放到系统 PATH 能访问的目录。不然你会发现开发机上程序能跑拿到客户机器上就报驱动无法加载。这就是为什么很多教程里强调“编译驱动只是开始部署才是大头”。5. Linux 环境下的编译与部署注意事项Linux 下如果只是开发调试通常不需要自己编译驱动装一个 Qt 的 SQL 驱动包就行。但到了生产环境或者要适配特定 MySQL 版本、静态链接场景还是绕不开源码编译这条路。5.1 包管理器已经解决的场景在 Ubuntu 或 Debian 系统里最容易的办法是sudo apt install libqt5sql5-mysql装完后驱动插件会出现在 Qt 的插件目录里比如/usr/lib/x86_64-linux-gnu/qt5/plugins/sqldrivers/qsqlmysql.so。这种情况适合绝大多数个人开发和内网部署。但如果你用 Qt 6包名会变。不同发行版里的 Qt SQL 驱动包名并不统一而且系统 Qt 版本往往比官方离线安装包里的 Qt 版本低。这时候我还是建议直接编译保持版本可控。5.2 库文件缺失与符号版本问题Linux 下常见的报错不是插件不存在而是插件找不到libmysqlclient.so的具体符号版本。原因是插件编译时链接的libmysqlclient.so.21目标机器上却只有老的.so.18。检查命令很直接ldd /path/to/qsqlmysql.so看一下输出里libmysqlclient.so那一行是否显示 not found。如果缺失可以手动指定库路径或重新编译插件并让它在运行时查找新的库。不要在多个路径里放不同版本的 MySQL 客户端库否则会出现符号错乱。5.3 关于 MariaDB 兼容协议很多团队用的是 MariaDB 服务器但 Qt 的插件名字仍然叫 QMYSQL。如果服务器是 MariaDB而客户端库使用 MariaDB 官方的连接库编译时也可以把路径指向 MariaDB 的头文件和库文件。这在一个模拟项目中试过基本能跑通。但有一点我吃过亏如果目标机器上只有 MariaDB 客户端库而插件是链接 MySQL 官方客户端库编译的那系统里就必须保证 MySQL 官方库也存在。兼容协议不代表二进制库可以完全互换运行时还是各找各的。最好的做法是编译前就确定生产环境的实际客户端库然后带着这个路径去编译插件。别等到部署时才做尝试Linux 下的动态库依赖比 Windows 更隐性。6. 验证驱动是否真正可用从驱动列表到连接测试驱动编译完成、插件也复制到位最后一步是验证。这一步不需要写复杂的业务逻辑只要做一个最小连接测试就能确认驱动是否真的被 Qt 加载。6.1 先看驱动列表在 Qt 里可以用QSqlDatabase::drivers()拿到当前可用的全部驱动名称#include QSqlDatabase #include QDebug int main(int argc, char *argv[]) { qDebug() QSqlDatabase::drivers(); return 0; }正常编译完 MySQL 驱动后输出里应该能看到QMYSQL和QMYSQL3。如果只看到QSQLITE说明插件没有被加载。这里有个细节驱动列表是在程序启动时扫描得到的。如果你是在 Qt Creator 的运行环境里测试一定要确认当前 Kit 使用的 Qt 插件目录是包含qsqlmysql.dll的那个。很多时候插件没加载不是插件本身坏了而是程序根本就没去那个目录找。6.2 最小连接测试代码驱动列表有 QMYSQL 之后就可以做真正的连接测试#include QSqlDatabase #include QSqlError #include QDebug int main(int argc, char *argv[]) { QSqlDatabase db QSqlDatabase::addDatabase(QMYSQL); db.setHostName(127.0.0.1); db.setPort(3306); db.setDatabaseName(test_db); db.setUserName(test_user); db.setPassword(test_pass); if (!db.open()) { qDebug() 连接失败: db.lastError().text(); return 1; } qDebug() 连接成功; db.close(); return 0; }如果这一步能输出“连接成功”说明插件加载、客户端库链接、网络连接都正常。如果报错常见原因有三种。6.3 从错误信息反推问题第一种错误是“QSqlDatabase: QMYSQL driver not loaded”这属于插件没找到或加载失败优先级最高的问题。去检查插件文件是否存在、位数是否正确、依赖的libmysql.dll是否在搜索路径里。第二种错误是“Authentication plugin caching_sha2_password cannot be loaded”常见于 MySQL 8.0 默认身份认证插件。这时候要么换成 MySQL 5.7 的账号认证方式要么升级 Qt 版本和客户端库版本让驱动支持新认证协议。第三种错误是“Host xxx is not allowed to connect to this MySQL server”这已经不是驱动问题了而是 MySQL 服务器端访问权限没放开属于网络配置范畴。别在 Qt 代码里浪费太多时间去检查 MySQL 的账号 host 授权。我个人习惯把db.lastError().text()完整打出来因为它往往比 Qt 弹窗里的提示信息更详细。排查顺序永远是插件加载 - 客户端库 - 网络 - MySQL 账号授权。最后再分享几个实战小技巧整套流程走完之后我额外攒了三条经验属于常规文档里不会细说的细节。第一条尽量保持 Qt 套件和编译工具链一致。MSVC 就一路 MSVCMinGW 就一路 MinGW别轻易在两个体系间横跳。这样能省下大量排错时间。第二条Windows 上可以用Dependencies这类工具检查qsqlmysql.dll的依赖动态库是否都正常它会很直观地告诉你缺少哪个 dll。别只盯着 Qt 插件目录客户端库缺失常常是驱动加载失败的隐形元凶。第三条在 CMake 配置阶段就确认 MySQL 是否被成功检测到别等编译完再去猜。配置完成后翻一下构建目录里的CMakeCache.txt确认MySQL_INCLUDE_DIR和MySQL_LIBRARY有值这一步只要几秒却能避免后面无谓重启工程。Qt 编译 MySQL 驱动这件事本身不算复杂但牵扯的环节多版本匹配、客户端库、编译器、插件目录、运行时部署。只要把每一步的前因后果理清楚照着上面的流程走Windows 和 Linux 下都能顺利编出可用的 QMYSQL 驱动。