如果你在 Qt 里用QSqlDatabase::addDatabase(QMYSQL)连接 MySQL大概率见过这个刺眼的报错QSqlDatabase: QMYSQL driver not loaded。我第一次碰到时还以为是 Qt 安装坏了重装两遍之后才发现官方安装包压根不保证给你提供 MySQL 驱动插件。QT编译安装MYSQL驱动这件事网上教程不少但坑更多——版本对不上、库不兼容、dll 找不到随便一个都能卡一下午。这篇文章把我从零编译到程序稳定连库的完整过程、踩过的坑和排查手段都整理出来希望能让你少走一遍这些弯路。无论你是 Qt 5 遗老还是 Qt 6 新兵编译器是 MSVC 还是 MinGW这套方法基本都适用。1. 为什么非折腾不可QMYSQL 驱动缺失的真实原因1.1 官方安装包不给 MySQL 插件的来龙去脉Qt 安装包为什么默认不给你 MySQL 驱动这个问题我最初也想不通后来查了下 Qt 的授权策略才算明白。Qt 官方为了规避授权链纠纷默认只编译内置的 SQLite 驱动因为 MySQL 的客户端库有自己的授权条款Qt 官方二进制包如果直接捆绑会带来额外的义务。所以你在Qt\版本号\编译器\plugins\sqldrivers目录下看到的通常只有qsqlite.dll顶多再有个qsqlodbc.dllMySQL 插件经常是缺失的。这不是 Bug是 license 的取舍。哪怕你用的某些安装包里面碰巧带了qsqlmysql.dll那个插件的编译版本也可能和你的 MySQL 客户端库对不上真正用起来照样报错。所以很多项目的依赖清单里都会有一条“手动编译 MySQL 驱动”的启动任务欠的债早晚要还。知道了原因就不必在这件事上浪费情绪了。驱动编译本身其实很快真正的成本在于配环境、链库、处理 dll 依赖。把原理理清楚之后后面换 Qt 版本、换编译器都能快速搞定。1.2 编译前先认清自己的工具链组合QMYSQL 驱动最大的坑是二进制兼容。你编译出来的qsqlmysql.dll是要被 Qt 运行时加载的所以它必须和你的 Qt 本体保持完全一致同一套编译器、同一个位数、同一种构建模式。MSVC 版 Qt 必须配 MSVC 编译的驱动MinGW 版 Qt 必须配 MinGW 编译的驱动混用基本就是“无法加载”。动手之前先做一次环境三连确认Qt 的位数。qmake -v或者看 Qt 安装目录名字里的mingw_64、msvc2019_64后缀先确认是 64 位还是 32 位。编译器的类型。MinGW 和 MSVC 生成的动态库格式不同插件不能互相使用。MySQL 客户端库的位数。libmysql 也分 32/64 位和插件位数不一致链接阶段就会出问题。另外注意一个很容易被忽略的点Qt 5 和 Qt 6 的构建体系不同。Qt 5 时代走的是 qmake进源码目录执行 qmake 就能编Qt 6 全面转向 CMake源码目录构建要借助qt-cmake包装器。后面的实操章节会分别给命令别拿 Qt 5 的教程硬套 Qt 6也别反过来。1.3 编译思路只有两条qmake 老路 / cmake 新路不管 Qt 版本怎么变编译 MySQL 驱动的本质只有一句话把 Qt 的 SQL 驱动源码和 MySQL 客户端库链接起来生成一个插件 dll。Qt 5 的源码在qtbase/src/plugins/sqldrivers下的mysql子目录qmake 通过-- MYSQL_INCDIR和-- MYSQL_LIBDIR把 MySQL 的头文件、库路径传给它然后跑sub-mysql目标编译插件。Qt 6 则是用 CMake 配置sqldrivers目录把MySQL_INCLUDE_DIR和MySQL_LIBRARY变量传给 CMake剩下的由构建系统完成。理解了这条主线遇到任何版本差异都不会慌。你只需要保证两件事源码目录找对MySQL 的库路径给对。2. 环境准备把依赖和路径一次理顺2.1 拿到正确的 MySQL C 连接器这里要先区分一个概念Qt 的 QMYSQL 驱动不是 MySQL 协议的完整实现它只是一个“外壳”真正负责 TCP 连接、认证协商、协议解析的是 MySQL 的 C API 客户端库也就是libmysql.dll以及配套的头文件。所以你必须先拿到 MySQL 的 C 连接器而不是什么 Java 连接器。有两种常见来源MySQL 服务端安装目录自带的include和lib适合本机测试。从 MySQL 官网下载 Connector/C 解压包里面有include、lib、bin/libmysql.dll适合独立环境。建议直接找解压版不要用安装版安装版不会把 include 和 lib 暴露到标准位置找起来麻烦。解压之后你需要的核心文件是include/mysql.hlib/libmysql.lib导入库链接阶段用bin/libmysql.dll运行时依赖发布阶段必须带上注意版本号。如果你连的是 MySQL 8.0就找 8.0 系列的 Connector/C如果服务端是 MariaDB也可以用 MariaDB Connector/C它和 MySQL 的 C API 高度兼容。2.2 检查 Qt 源码包与编译器环境编译驱动需要 Qt 的源码很多人的安装包里根本没有这段源码。Qt 5 需要在安装时勾选 “Sources” 组件Qt 6 同样是Src组件。当初没勾选的话打开 Qt 维护工具添加组件里找到 Sources补装即可。装好后确认路径是类似这样的结构C:\Qt\5.15.2\Src\qtbase\src\plugins\sqldrivers C:\Qt\6.5.3\Src\qtbase\src\plugins\sqldrivers这个sqldrivers目录下除了 mysql还有 sqlite、odbc 等一组驱动源码我们只编 mysql 子目标就行。另外还要确认使用的命令行环境。Qt 安装时会在开始菜单生成快捷方式比如 “Qt 5.15.2 (MinGW 8.1.0 64-bit)”或者 Qt 6 的对应项。从快捷方式打开终端它会自动把 qmake、编译器、CMake 工具的路径配好。不要自己手动拼一串环境变量容易串版本尤其是电脑上装了多个 Qt 的时候。2.3 规划一个无空格的干净目录结构这一步看着不起眼实际能省很多麻烦。把 MySQL 的依赖目录放到无空格、短路径的目录下例如C:\dev\mysql\ include\ lib\ bin\ C:\build\sqldrivers\为什么不要放在C:\Program Files\MySQL\MySQL Server 8.0这种路径因为 qmake 解析变量时路径里的空格会被当成参数分隔符轻则路径截断重则编译失败。Qt 5 的 qmake 对带空格的路径尤其敏感。你可以在编译时想办法加引号规避但最简单粗暴的办法就是一开始就把依赖放在干净目录。如果你手头只有 MySQL 安装版把它的include和lib目录整个复制到C:\dev\mysql下面再记录一下 MySQL 安装目录里的bin路径后面验证连接时会用到mysql.exe和mysqld.exe。3. 编译实操Qt 5 走 qmakeQt 6 走 cmake3.1 Qt 5 MinGW 编译的完整命令我以 Qt 5.15.2 MinGW 8.1.0 64 位为例走一遍流程。打开 “Qt 5.15.2 (MinGW 8.1.0 64-bit)” 命令行快捷方式然后进入 sql 驱动源码目录cd C:\Qt\5.15.2\Src\qtbase\src\plugins\sqldrivers执行 qmake把 MySQL 依赖路径传进去qmake -- MYSQL_INCDIRC:\dev\mysql\include MYSQL_LIBDIRC:\dev\mysql\lib mingw32-make sub-mysql编译完成后到C:\Qt\5.15.2\mingw_64\plugins\sqldrivers目录下看应该能找到qsqlmysql.dllrelease和qsqlmysqld.dlldebug文件大小一般几百 KB 到 1MB 左右。这里有个特别重要的观察点qmake 在做库检测时如果没找到它认识的 MySQL 库不会报错而是直接跳过 MySQL 插件。所以你执行完 qmake 之后不要急着跑 make先看日志里有没有类似 “mysql disabled” 或 “No MYSQL library found” 的提示。如果有说明 MYSQL_LIBDIR 路径不对或者目录里的库文件名不符合它的预期。我见过有人卡了两天才发现是库没找到qmake 静默把插件禁用了。关于库文件MinGW 还有一个经典坑libmysql.lib通常是 MSVC 编译的MinGW 的链接器可能不认。报错通常是cannot find -lmysql。解决办法是用gendef和dlltool从libmysql.dll生成一个 MinGW 能用的导入库libmysql.agendef libmysql.dll dlltool -d libmysql.def -l libmysql.a -D libmysql.dll然后把生成的libmysql.a放在C:\dev\mysql\lib目录下。如果你不想折腾这个另一个省事方案是换用 MariaDB Connector/C它长期提供 MinGW 可用的二进制包头文件和 MySQL 兼容。3.2 Qt 6 MinGW 编译的推荐姿势Qt 6 的构建方式换成 CMake但目录还是那个 sqldrivers。我以 Qt 6.5.3 MinGW 64 位为例。先建一个干净的构建目录然后用qt-cmake配置mkdir build-sqldrivers cd build-sqldrivers C:\Qt\6.5.3\mingw_64\bin\qt-cmake.exe C:\Qt\6.5.3\Src\qtbase\src\plugins\sqldrivers ^ -DCMAKE_BUILD_TYPERelease ^ -DCMAKE_INTERNAL_BUILDON ^ -DMySQL_INCLUDE_DIRC:\dev\mysql\include ^ -DMySQL_LIBRARYC:\dev\mysql\lib\libmysql.lib配置无误后编译cmake --build . --target mysql为什么要用qt-cmake.exe而不是裸的cmake因为qt-cmake会帮你把 Qt 的CMAKE_PREFIX_PATH和工具链路径都设置好裸 cmake 还要手动配一堆变量。-DCMAKE_INTERNAL_BUILDON也很关键sqldrivers 目录本身不是按独立顶层项目设计的不加这个变量 CMake 可能会在检查阶段就报错。编译产物默认会输出到 Qt 安装目录的plugins\sqldrivers下也就是C:\Qt\6.5.3\mingw_64\plugins\sqldrivers\qsqlmysql.dll。如果你不想污染 Qt 安装目录可以在编译完成后把 dll 备份到一个专门的目录放到工程或发布包里。Qt 6 的 Debug/Release 插件命名和 Qt 5 类似Debug 构建出来是qsqlmysqld.dllRelease 是qsqlmysql.dll。3.3 MSVC 工具链的额外注意事项使用 MSVC 版 Qt 的朋友流程和 MinGW 大同小异但要注意几点。第一必须用 Qt 安装时自带的那个 “Qt 6.5.3 (MSVC 2019 64-bit)” 命令行快捷方式启动环境它会调用vcvarsall.bat配置 MSVC 环境。如果你直接用 cmd会报找不到 cl.exe。第二MSVC 构建时MySQL 官方提供的libmysql.lib可以顺利链接不存在 MinGW 那种导入库格式问题。MSVC 用户编译过程一般最顺利只要路径给对了基本一把过。第三CMake 的配置命令稍有区别。MSVC 是多配置生成器不能靠CMAKE_BUILD_TYPE控制编译模式要在构建时加--config Release或--config Debugcmake --build . --target mysql --config Release第四新版 MySQL 的libmysql.dll会依赖 OpenSSL 的 dll 文件后面细说MSVC 和 MinGW 都会遇到运行时缺了照样连不上。4. 部署与验证驱动装上只是开始4.1 插件该放的位置和该带上的 dll编译出qsqlmysql.dll只是第一步把它放到正确的位置才算真正可用。插件有两种放法放进 Qt 安装目录的plugins\sqldrivers下开发环境下所有使用该 Qt 版本的程序都能加载。放进你的程序可执行文件同级的sqldrivers目录下这是发布程序时的标准方式Qt 会优先在 exe 目录附近查找插件。发布时的最小目录结构长这样发布目录/ ├─ 你的程序.exe ├─ libmysql.dll ├─ libssl-3-x64.dll ├─ libcrypto-3-x64.dll ├─ platforms/ │ └─ qwindows.dll └─ sqldrivers/ └─ qsqlmysql.dll注意libmysql.dll必须放到 exe 同级目录或者系统 PATH 里。程序启动时加载qsqlmysql.dll的同时会解析它的依赖 dll如果找不到libmysql.dll插件加载就会失败症状就是Driver not loaded。这个报错具有巨大的迷惑性你会以为是插件编译有问题实际上只是依赖没带全。还有一个常见叠加项如果你的 MySQL 客户端库是 8.0.30 之后的版本libmysql.dll依赖libssl-3-x64.dll和libcrypto-3-x64.dll这几个 dll 在 MySQL 安装目录的bin下一并带上。只带 libmysql 不带 OpenSSL 的 dll一样会加载失败。4.2 用 QSqlDatabase 快速验证驱动驱动放好之后花两分钟写一个最小测试程序把连接链路整体验证一遍。新建一个 Qt 工程pro 文件这样写QT core sql CONFIG console CONFIG - app_bundle TARGET testmysql SOURCES main.cppmain.cpp 这样写#include QCoreApplication #include QSqlDatabase #include QSqlError #include QDebug int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() available drivers: QSqlDatabase::drivers(); QSqlDatabase db QSqlDatabase::addDatabase(QMYSQL); db.setHostName(127.0.0.1); db.setPort(3306); db.setDatabaseName(test); db.setUserName(root); db.setPassword(123456); if (!db.open()) { qDebug() open failed: db.lastError().text(); return 1; } qDebug() open ok, connected to db.hostName(); return 0; }这里面有几条关键信息值得看QSqlDatabase::drivers()会打印当前 Qt 能加载的驱动列表。如果里面有QMYSQL说明驱动插件加载成功如果没有说明插件没放对位置或依赖缺失。open()返回 false 时db.lastError()的文本信息量很大。常见的有Access denied for user账密错误或权限不足。Unknown MySQL server host主机名解析失败。SSL connection error认证或 SSL 协商有问题。Authentication plugin ... cannot be loaded客户端库版本太老这个后面专门讲。我自己列过一个小经验先看drivers()里有没有 QMYSQL再决定往哪个方向排查。凡是插件加载问题绝不会走到open()这一步凡是走到open()报认证、网络、权限错误的插件本身基本是好的。4.3 发布程序时最容易漏掉的细节开发机上跑通不算本事程序拿到另一台电脑还能连库才算。这里有几个反复踩的坑给你列一下第一windeployqt不会帮你带 MySQL 相关的 dll。它只负责 Qt 自身的运行时如 platforms、core、network、sql 基础库libmysql.dll、libssl这些第三方依赖不在它的职责范围内。执行完windeployqt之后还要手动把 MySQL 的 dll 复制到发布目录。第二插件文件名不能改。qsqlmysql.dll这个名字是 Qt 按约定找的改成mysql.dll或者别的名字系统直接忽略。第三判断插件加载失败原因时可以设置环境变量QT_DEBUG_PLUGINS1。运行程序时控制台会输出插件加载的详细日志比如Cannot load library ...\sqldrivers\qsqlmysql.dll: The specified module could not be found.这个日志能直接告诉你缺的是哪个依赖比瞎猜高效得多。第四还有一个快速解脱手段在 exe 同级放一个qt.conf内容写[Paths]和Plugins.。这样 Qt 会在当前目录找插件省得每次都要把插件放到 Qt 安装目录才能跑。5. 常见问题排查实录5.1 Driver not loaded 的定位三板斧Driver not loaded算得上 Qt 连接 MySQL 的第一大报错排查思路看起来五花八门其实就三板斧。第一步开QT_DEBUG_PLUGINS1。这是最重要的手段很多问题在这一步就水落石出。程序输出会告诉你 Qt 尝试加载哪个路径下的 dll以及加载失败的具体原因。如果是 “The specified module could not be found”基本可以确定是某个依赖 dll 缺失。第二步检查QSqlDatabase::drivers()的输出。列表里没有 QMYSQL就说明插件没有被成功加载。这时去确认qsqlmysql.dll是否在sqldrivers目录下以及插件位数是否和 Qt 一致。第三步用 Dependencies 或者 dumpbin 查看qsqlmysql.dll的依赖树。dumpbin /dependents qsqlmysql.dll会列出它依赖的所有 dll你逐个对照发布目录缺谁补谁。这个方法能精准定位libmysql.dll、libssl-3-x64.dll这类隐藏依赖。这三板斧走完至少能解决 90% 的驱动加载问题。剩下的少数问题一般在位数或编译器一致性上。5.2 认证插件与 libmysql 版本冲突MySQL 8 发布之后很多老项目突然连不上数据库报的错五花八门常见的有Authentication plugin caching_sha2_password cannot be loadedSSL connection error: error:00000000Access denied for user xxxlocalhost (using password: YES)第一眼看上去像是权限问题实际多半是libmysql.dll版本太老的锅。MySQL 8 默认的认证插件是caching_sha2_password老的客户端库不认识这个插件认证流程直接中断。注意一点Qt 的 QMYSQL 插件本身不负责实现认证它只是把认证工作转发给 libmysql。所以遇到这个报错别急着换 Qt 版本、改驱动源码先把运行目录下的libmysql.dll换成新版 Connector/C 试试。我实际测下来MySQL 8.0 的服务端配 MySQL 8.0.30 以上版本的 Connector/C认证基本没问题。MySQL 8.4 以后服务端默认禁用了老式的mysql_native_password如果还想用老客户端需要额外配置服务端但生产环境不建议为了兼容老客户端降低安全性。还有一个推荐方案用 MariaDB Connector/C 替换 libmysql。它对 MySQL 8 的认证支持很完善API 兼容而且自带 MinGW 可用的库对 Windows 下编译比较友好。如果你在 MinGW 工具链上被libmysql.lib格式问题折磨过可以直接切到 MariaDB 这条线。5.3 一张表理清版本错配问题下面这张表是我在多次折腾中总结出来的几乎涵盖了我遇到过的所有因为版本错配引发的问题现象常见原因解决办法运行时提示 qsqlmysql.dll 不是有效的 Win32/64Qt 位数与插件位数不一致用相同位数 Qt 重新编译驱动加载插件报 “unknown file format”MSVC 版插件放进 MinGW 版 Qt确保插件构建器和 Qt 构建器一致cannot find -lmysqlMinGW 无法使用 MSVC 的 .lib 文件用 dlltool 生成 libmysql.a或换 MariaDB无 QMYSQL 驱动列表但编译日志正常qmake/CMake 没找到 MySQL 库确认 MYSQL_INCDIR/MYSQL_LIBDIR 路径open 时认证插件无法加载libmysql.dll 版本过旧换新版 Connector/C或改服务端认证插件能连接但中文乱码连接未指定字符集服务端建库用 utf8mb4连接后执行 SET NAMES utf8mb4服务器上连接超时防火墙、root 仅允许 localhost建远程账号并授权检查 3306 端口最后分享一个小技巧编译折腾完把MYSQL_INCDIR、MYSQL_LIBDIR对应的依赖目录整体备份并标注版本号。以后换 Qt 版本或者换电脑直接拿备份重新编译不用重新下载五分钟就能出驱动。我自己这么做之后再也没有为驱动编译这件事卡过壳。