说实话,Qt自带的SQL驱动里偏偏少了MySQL,这事儿我折腾过不止一次。每次在新环境配好Qt、写好连接串,一跑就报QSqlDatabase: MYSQL driver not loaded,心情瞬间就凉了半截。后来把qtbase/src/plugins/sqldrivers/mysql这个目录翻了个底朝天,总算是把编译MySQL驱动的全过程捋顺了。
这篇博文就把我编译 Qt MySQL 驱动的完整过程、踩过的坑、以及编译完怎么部署全都写出来。不管你是Windows下用MinGW还是MSVC,还是Linux环境编译,看完都能照着一步步搞定。我默认你至少用过Qt的SQL模块,知道QSqlDatabase、QSqlQuery这几个基本类,但没自己编译过插件。
1. 为什么需要自己编译MySQL驱动
1.1 Qt官方包缺MySQL驱动的原因
很多人第一次遇到这个问题时都一脸懵:Qt明明自带了SQLite驱动,为什么MySQL驱动要自己编译?这不是你下载的Qt包有问题,而是官方有意为之。MySQL的客户端库采用的是GPL授权协议,跟Qt开源的LGPL协议存在授权兼容问题,所以官方预编译包里默认不包含MySQL插件,只保留了SQLite、ODBC这些相对“安全”的驱动。
你打开Qt安装目录下的plugins/sqldrivers/文件夹看一眼就明白了:里面有qsqlite.dll、qsqlodbc.dll,但就是没有qsqlmysql.dll。这直接导致QSqlDatabase::isDriverAvailable("QMYSQL")返回false,任何尝试连接MySQL的操作都会在驱动加载阶段就失败。
1.2 什么样的场景需要自己编译
如果你只是用SQLite做本地存储,完全不需要折腾这个。但一旦你的项目要衔接后端MySQL数据库——比如做的桌面客户端要连公司服务器、要读写线上业务数据,或者做的是带用户系统的管理工具——就必须自己把MySQL驱动编译出来。
还有一个容易被忽略的场景:即使你拿到了别人编译好的qsqlmysql.dll,也未必能直接用。Qt编译器版本不匹配(MinGW vs MSVC)、Qt主版本不匹配(Qt5 vs Qt6)、甚至位数不匹配(32位 vs 64位)都会导致驱动加载失败。最稳妥的办法就是在你的目标环境里亲自编译一次,保证驱动跟你的Qt版本完全对应。
我的建议是:如果你要在多个项目里用MySQL,花一次时间把编译流程走通,之后所有项目都能直接复用,这笔时间花得值。
2. 编译前的环境准备与选型
2.1 确认你的Qt版本和编译器类型
打开Qt安装目录,最直接的方法是看Qt文件夹下的目录结构。如果你装的是Qt 5.15,路径通常是Qt/5.15.2/下分mingw81_64、msvc2019_64等目录;如果是Qt 6.x,则是Qt/6.5.0/下分mingw_64、msvc2019_64等。
这一步特别关键,因为你要保证编译驱动用的编译器跟编译Qt本身的是同一套。用MinGW版Qt配MSVC编译出来的驱动,运行时大概率直接报错。我一开始就犯过这个错,用了MSVC编译的插件配MinGW版Qt,结果driver not loaded的报错依然如故,白折腾半天。
从Qt 6开始官方也提供CMake方式编译驱动,但我觉得只要能用qmake还是优先用qmake,因为流程更直白,也更容易排查问题。
2.2 需要准备的材料清单
先说结论,再说为什么要这些材料。
- Qt源码包:需要下载与你安装的Qt版本完全一致的源码。比如你装的是Qt 5.15.2的MinGW版,就要下载
qtbase模块源码,版本也要对应5.15.2 - MySQL客户端库:不需要装完整版MySQL Server,但至少要安装MySQL Connector/C,或者直接从一个已安装的MySQL目录里拿到
include和lib目录 - 编译器:跟你Qt版本匹配,MinGW或MSVC
- 系统环境变量:如果你用MinGW,要保证
PATH里能找到g++和qmake
我实际测试下来,MySQL Connector/C是个不错的选择,它专门提供开发所需的头文件和库文件,不会像完整装MySQL Server那样带上一堆用不上的服务程序。当然,如果你本机恰好装了MySQL Server,直接指定安装目录里的include和lib也不是不行,只是路径要写对。
2.3 源码包获取和目录定位
Qt源码你不需要下载整个qt5或qt6大包,只需要qtbase模块就够了。以Qt 5.15.2为例,下载解压后进入qtbase/src/plugins/sqldrivers目录,这里面能看到mysql子目录,还有sqlite、odbc等子目录,驱动插件源码都在这里。
有一个细节需要注意:sqldrivers目录下的项目是靠qsqldriverbase.pri和qsqldriverbase.pro这套机制管理子模块的。你直接qmake整个sqldrivers目录时,它会尝试编译所有启用的驱动。如果你只想编译MySQL驱动,参数里一定要指定MYSQL_INCDIR和MYSQL_LIBDIR,否则qmake会认为MySQL不可用而跳过它。
3. 核心原理:MySQL驱动插件是怎么工作的
3.1 插件机制的加载流程
在深入编译之前,有必要搞清楚插件插件是怎么被加载的。Qt的SQL驱动是以插件形式存在的,本质上就是一个动态链接库,文件名规则是qsqlxxx.dll(或.so)。运行时,QSqlDatabase::addDatabase("QMYSQL")会去plugins/sqldrivers/目录搜索这个插件,加载成功后才会向驱动注册。
isDriverAvailable("QMYSQL")这个静态函数就是纯粹检测插件目录里是否有对应文件,以及该文件能否被Qt正确识别。如果插件文件存在但加载失败——比如编译器不匹配、依赖的MySQL客户端库缺失——这个函数同样返回false。
编译驱动看起来复杂,本质就一件事:把MySQL驱动源码编译成一个可加载的插件文件,放到Qt的插件目录里,并保证它运行时能找到所需的依赖库。
3.2 编译的本质是链接MySQL客户端库
MySQL驱动插件本身只是个“桥梁”,真正的数据库通信靠的是MySQL客户端库。也就是说,插件里调用了mysql_init、mysql_real_connect、mysql_query这些C API函数,而这些函数的实现存在客户端库里。
这就解释了两个关键问题。第一,为什么编译时需要指定MYSQL_INCDIR和MYSQL_LIBDIR?因为编译器需要找到mysql.h头文件来确认函数声明,链接器需要找到libmysql库来解析函数引用。第二,为什么运行时还要把客户端库拷贝到程序目录?因为插件加载后需要动态链接这个库,系统PATH里找不到它就会加载失败。
用一个生活化的类比:你编译的插件是一台电器的外壳和电路板,但电源适配器(客户端库)是另一家公司提供的。你不光要在组装时接好适配器的接口标准,还要在用户使用时让机器找得到适配器。
3.3 Qt5与Qt6在编译方式上的差异
从Qt 5到Qt 6,驱动编译流程有一些变化,但万变不离其宗。Qt 5时代,你可以在qtbase/src/plugins/sqldrivers目录下执行qmake -- MYSQL_INCDIR=... MYSQL_LIBDIR=...,然后make && make install一次搞定。
Qt 6时代,一种方式仍然可以,另一种是进入mysql子目录,用CMake指定MYSQL_INCDIR、MYSQL_LIBDIR和CMAKE_PREFIX_PATH,通过cmake --build .编译。如果你的Qt 6是用官方安装器装的,源码需要额外在安装器里勾选Sources组件才能拿到。
还有一个小坑:Qt 6.4以后,如果你把Qt源码目录放在非ASCII路径,CMake会直接报错。源码路径尽量用纯英文,不然编译到一半崩了会让你怀疑人生。
4. 完整编译流程实操
4.1 Windows + MinGW 编译(最常用场景)
这是我最常用的组合,也是遇到问题最少的一条路。整体流程分五步。
第一步,准备目录。假设你的Qt安装在C:\Qt\5.15.2\mingw81_64,Qt源码解压在C:\qt-src\5.15.2\qtbase,MySQL Connector/C安装或解压在C:\mysql-connector。注意mysql-connector目录下要有include和lib两个文件夹。
第二步,打开终端并设置MinGW环境变量。不要双击Qt Creator里的终端,最好是手动打开命令行,然后手动把MinGW的bin目录加进PATH:
set PATH=C:\Qt\5.15.2\mingw81_64\bin;C:\Qt\Tools\mingw810_64\bin;%PATH%这里的路径以你实际安装目录为准,关键是qmake.exe和mingw32-make.exe都能被找到。
第三步,进入源码目录并执行qmake:
cd C:\qt-src\5.15.2\qtbase\src\plugins\sqldrivers qmake -- MYSQL_INCDIR="C:\mysql-connector\include" MYSQL_LIBDIR="C:\mysql-connector\lib"这一句qmake执行完,如果输出里能看到MySQL相关的提示,说明环境变量生效了。如果没有任何反应,多半是qmake没有识别到你指定的MySQL路径,后续编译会跳过MySQL驱动模块。
第四步,执行编译。进入mysql子目录单独编译,也可以直接在sqldrivers目录里全量编译,但单独编译MySQL更省时间:
cd mysql mingw32-make编译输出正确的结果应该生成qsqlmysql.dll文件。如果中途报错“cannot find -lmysql”之类的信息,说明链接器找不到MySQL客户端库,检查第三步的路径参数是否有误。
第五步,部署。把生成的qsqlmysql.dll复制到Qt的插件目录C:\Qt\5.15.2\mingw81_64\plugins\sqldrivers\。同时把MySQL客户端库libmysql.dll复制到你的可执行文件同级目录,驱动才能真正跑起来。
优先级提醒:Qt插件目录里的qsqlmysql.dll必须与你的Qt版本、编译器完全对应。MinGW编译的插件不能放在MSVC版的Qt插件目录里混用,否则加载时会静默失败。
4.2 Windows + MSVC 编译与命令行要求
如果你用的是MSVC版Qt,流程跟MinGW大同小异,但有几个不同点。
首先,MSVC编译器必须在“开发者命令提示符”里运行,也就是安装了Visual Studio后自带的那种命令行环境,里面已经配置好了cl.exe、nmake.exe等工具。直接用普通命令行打开会报找不到编译器。
其次,qmake生成的Makefile默认是NMake格式,编译命令要用nmake而不是mingw32-make。
cd C:\qt-src\5.15.2\qtbase\src\plugins\sqldrivers qmake -- MYSQL_INCDIR="C:\mysql-connector\include" MYSQL_LIBDIR="C:\mysql-connector\lib" cd mysql nmakeMSVC环境下还有一个历史遗留问题:老版本的MySQL Connector/C提供的库文件名可能是libmysql.lib,而Qt 5.15及以上版本链接时找的是mysql.lib。如果编译报错找不到mysql.lib,检查C:\mysql-connector\lib下实际文件名,然后手动创建同名副本就行了,方法是在lib目录里执行:
copy libmysql.lib mysql.lib这个问题我帮别人处理过三次,每次都是这个原因,排查时多留意一眼 lib 目录里到底有哪些文件。
4.3 Linux 下编译 MySQL驱动
Linux下编译相对简单,因为不需要关心dll路径问题。第一步安装依赖,以Ubuntu/Debian为例:
sudo apt update sudo apt install libqt5-dev qtbase5-dev libmysqlclient-dev第二步,如果你的Qt是系统包管理器装的,源码一般在/usr/src/qt5或通过额外包提供,路径不太好找。更推荐的方法是下载qtbase源码包:
tar -xzf qtbase-everywhere-src-5.15.2.tar.gz cd qtbase-everywhere-src-5.15.2/src/plugins/sqldrivers第三步,用qmake指定MySQL库路径:
qmake -- MYSQL_INCDIR="/usr/include/mysql" MYSQL_LIBDIR="/usr/lib/x86_64-linux-gnu"这里不需要指定库名,因为Qt的源码里已经写死了-lmysqlclient,只要系统装了libmysqlclient-dev就能链接到。执行make -C mysql编译,生成libqsqlmysql.so:
cd mysql make -j4第四步,部署时把libqsqlmysql.so复制到Qt插件目录。系统包装的Qt插件目录一般是/usr/lib/x86_64-linux-gnu/qt5/plugins/sqldrivers/,你可以用qmake -query QT_INSTALL_PLUGINS获取准确路径。
Linux下最容易踩的坑是只编译不部署。很多人编译完发现程序还是报driver not loaded,实际上是插件根本没放进插件目录。这一步至关重要。
4.4 部署细节与驱动验证方法
编译完成后,推荐用一个验证脚本来确认驱动是否加载成功。测试代码就写个最小化的Qt控制台程序:
#include <QCoreApplication> #include <QSqlDatabase> #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); qDebug() << "Available drivers:" << QSqlDatabase::drivers(); if (QSqlDatabase::isDriverAvailable("QMYSQL")) { qDebug() << "MYSQL driver loaded successfully"; } else { qDebug() << "MYSQL driver not loaded"; } return 0; }编译运行时把这小工具放在你的Qt环境目录下,直接qmake && make即可。输出里如果drivers列表中有QMYSQL字样,就说明插件部署成功。
部署后我还建议做一个“最小连接测试”,用一个临时数据库或本机MySQL实例,执行一次db.open()并isOpen()验证。这一步能一次性排掉dll依赖、端口、账号权限等一堆后续问题。
5. 常见问题与系统化排查
5.1 编译期报错的对应关系
我在多次编译中积累了一张问题对照表,实用性很强。
| 错误现象 | 根本原因 | 解决方法 |
|---|---|---|
mysql.h: No such file or directory | 没找到头文件 | 确认MYSQL_INCDIR路径下存在mysql.h |
cannot find -lmysqlclient | 没找到链接库 | 确认MYSQL_LIBDIR路径正确,Linux下需装libmysqlclient-dev |
cannot find -lmysql | 库命不匹配 | Windows下检查libmysql.lib是否存在,必要时复制为mysql.lib |
| 编译通过但插件加载失败 | 插件与Qt编译器不匹配 | 检查MinGW/MSVC类型是否一致 |
| 编译时MySQL模块被跳过 | qmake没识别到MySQL路径 | 重新执行带-- MYSQL_INCDIR=... MYSQL_LIBDIR=...参数的qmake |
第一个错误是最常见的,群里十个人里至少有六个人卡在这里。很多人以为装完MySQL Server就可以编译了,但Server安装目录里的include其实不是开发用的完整头文件集。如果你用Connector/C,安装完默认路径下是能直接找到mysql.h的;如果你只装了Server,就得专门去下载对应版本的Connector或者从源码包里提取头文件。
5.2 运行时驱动不加载的排查思路
QSqlDatabase: MYSQL driver not loaded这个报错百分之八十是两种原因:插件不在目录,或者依赖库缺失。
先检查插件目录有没有qsqlmysql.dll(或.so),没有就回到第4步重新部署。有的话,用Dependency Walker或者Process Explorer这类工具查看这个插件的依赖,Windows下最常见的缺失是libmysql.dll。MinGW编译的插件依赖的是MinGW版的libmysql.dll,MSVC同理,混用也可能导致加载失败。
这里有一个排查技巧:用QMessageBox弹窗或者qDebug输出QSqlDatabase::drivers(),如果列表里压根没有QMYSQL,说明插件压根没被识别;如果列表里有QMYSQL但连接时依然失败,说明插件加载了但初始化过程出了问题(比如链接库的版本不匹配)。
5.3 MySQL 8.x 认证插件兼容性问题
这句话请你务必记住:即使驱动编译成功、dll也部署到位,连接MySQL 8.0以上数据库时仍有大量人栽在认证环节。MySQL 8.0默认使用的caching_sha2_password认证插件,老版本的Qt驱动是不支持的,编译时不会报错,运行时却会报类似Authentication plugin 'caching_sha2_password' cannot be loaded的错误。
解决方案有三种。第一,升级Qt到5.14以上或6.x版本,新版驱动的代码里已支持该认证插件;第二,把MySQL账号的认证插件改回mysql_native_password:
ALTER USER 'youruser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword'; FLUSH PRIVILEGES;第三,如果升级成本和改账号都不方便,可以在MySQL端启用default_authentication_plugin=mysql_native_password配置并重启服务。
我个人建议优先考虑改账号插件或升级Qt。全局改默认验证方式会影响所有新建用户,如果某组织里数据库权限不在你手上,改账号方式更灵活,只影响你负责的那个账号。
5.4 最后再分享一个部署小技巧
我实际操作中还有一个体会:部署驱动时不仅要拷贝qsqlmysql.dll,还要特别注意MySQL客户端库的版本。MySQL客户端库太老可能导致连接新版本服务时出现未知协议错误;太新则可能与老版服务不兼容。稳妥的做法是让客户端库版本不低于服务端版本,且尽量用官方发布的最新稳定版。
另外提醒一个Windows下容易坑人的地儿:如果你的程序目录、Qt插件目录、MySQL的bin目录同时在PATH里,系统加载dll时会按PATH顺序查找。我在某家公司协助排查过一次诡异问题,同样的程序在一台机器上正常、另一台机器上报driver not loaded,最后发现是后者PATH里残留了一个老旧的libmysql.dll,被优先加载了。解决办法是把Qt插件目录和程序目录从PATH中直接去掉,或者调整顺序让程序目录排在最前。
6. 从编译到长期维护的一点体会
把整套流程跑通之后,我最大的感慨是:编译本身不算难,难的是把背后的依赖关系和加载机制彻底理解。你明白驱动是个插件、插件要链接客户端库、运行时还要找到依赖库这三点,就掌握了排除大多数问题的主动权。
这个过程中我踩过的最深的坑是版本混用——Qt 5.12的源码配Qt 5.15的编译器环境,看起来都是5.x,编译也能过,但插件就是加载失败。后来养成一个习惯,每次编译前先qmake --version确认当前用的qmake跟目标Qt完全匹配,这个动作几乎能避免一半以上的编译期和运行期问题。
如果你编译完驱动,后续想在项目里直接用,还有一个小建议:像这类第三方依赖,最好在工程文档里记录清楚Qt版本、编译器类型、MySQL客户端库版本这三个信息。三个月后你再回来维护项目,大概率已经忘了当时是怎么配的,有记录能省下一两天的排查时间。我个人是吃过这个亏的,现在都习惯性地补一份环境说明。