1. 这个报错不是代码写错了,而是PyQt5根本没“看见”MySQL驱动
你刚在PyQt5里写下这行代码:
db = QSqlDatabase.addDatabase("QMYSQL") db.setHostName("localhost") db.setDatabaseName("testdb") db.setUserName("root") db.setPassword("123456") if not db.open(): print(db.lastError().text())运行后控制台只甩给你一句冰冷的Driver not loaded—— 没有堆栈、没有路径提示、没有具体模块名,连个错误码都懒得给。你翻遍自己写的逻辑,确认host、port、user、password全对;用命令行mysql -u root -p能正常登录;Navicat连得稳稳当当;甚至用pymysql或mysql-connector-python写个简单脚本也能查出数据……可偏偏 PyQt5 就是死活加载不了驱动。
这不是你的代码问题,也不是MySQL服务的问题,更不是密码输错了——这是 PyQt5 的数据库驱动加载机制和你本地环境之间的一场“失联”。它不像 Python 的import pymysql那样靠sys.path查找模块,也不像 Java 的 JDBC 那样靠 classpath 加载 jar 包。PyQt5 的QSqlDatabase是通过 Qt 的插件系统(Plugin System)在运行时动态加载.dll(Windows)或.so(Linux/macOS)文件的,而这个加载过程完全脱离 Python 解释器的控制范围,发生在 C++ 层。一旦 Qt 找不到对应驱动的二进制文件,或者文件依赖缺失、架构不匹配、路径未注册,它就只会吐出那句万能又无用的Driver not loaded。
我第一次遇到这个问题是在部署一个内部资产管理系统时。开发机上一切正常,打包成 exe 后发给同事,双击就弹窗报错。同事反复重装 PyQT5、重装 MySQL、重配环境变量,折腾三天毫无进展。最后发现:他电脑上装的是 MySQL 8.0.33 的 x64 安装版,而我打包用的 PyQt5 是从pip install PyQt5==5.15.19装的官方 wheel,它自带的qsqlmysql.dll只链接了 MySQL 5.7 的libmysql.dll。同事机器上根本没有libmysql.dll,系统 PATH 里也没有指向 MySQL 安装目录的 bin 文件夹——Qt 插件加载器在C:\Windows\System32、C:\Python39\Library\plugins\sqldrivers、exe所在目录\sqldrivers这几个固定位置翻了个底朝天,最终两手一摊:“Driver not loaded”。
所以,别急着改 Python 代码。先问自己三个问题:
- 你的 PyQt5 是怎么装的?是 pip 官方 wheel?conda?还是从源码编译?
- 你的 MySQL 是怎么装的?是官网下载的 MSI 安装包?zip 免安装版?还是通过 XAMPP/WAMP 附带的?
- 你的操作系统是 32 位还是 64 位?Python 是 32 位还是 64 位?MySQL 是 32 位还是 64 位?这三个“位数”必须严格一致,差一位,
qsqlmysql.dll就会因 ABI 不兼容而被 Qt 直接忽略。
这个报错的本质,是 Qt 的插件加载器在执行QLibrary::load()时失败了,而失败原因被 Qt 封装成了统一的字符串。它不告诉你缺了哪个 DLL,不告诉你路径在哪,甚至不告诉你当前搜索了哪些目录——它只负责“加载失败”,把解释权留给了开发者。接下来我们要做的,就是绕过这个黑箱,亲手把它撬开。
2. 驱动加载的完整路径:从 Qt 插件目录到 libmysql.dll 的生死链
要真正解决Driver not loaded,你必须理解 Qt 加载数据库驱动的完整链条。这不是一个简单的“复制文件到某目录”就能搞定的操作,而是一条环环相扣的依赖链。我们以 Windows 系统为例(Linux/macOS 原理相同,只是文件扩展名和路径分隔符不同),拆解这条链路上每一个关键节点。
2.1 Qt 插件目录:驱动文件的法定“户籍所在地”
Qt 在启动时会扫描一系列预设目录,寻找sqldrivers子目录,并从中加载.dll文件。这些目录按优先级从高到低排列如下(可通过QApplication.libraryPaths()查看):
| 优先级 | 目录路径 | 说明 |
|---|---|---|
| 1 | ./sqldrivers(当前可执行文件所在目录下的子目录) | 打包工具(如 PyInstaller)最常放驱动的地方,最高优先级,也是最推荐的部署方式 |
| 2 | ./plugins/sqldrivers(当前可执行文件所在目录下的 plugins 子目录) | 传统 Qt 应用常用结构 |
| 3 | C:\Python39\Lib\site-packages\PyQt5\Qt5\plugins\sqldrivers | pip 安装 PyQt5 时的默认位置,但仅对直接运行 .py 文件有效,对打包后的 exe 无效 |
| 4 | C:\Users\<user>\AppData\Local\Programs\Python\Python39\Lib\site-packages\PyQt5\Qt5\plugins\sqldrivers | 用户级安装路径,同上 |
| 5 | C:\Qt\5.15.2\mingw81_64\plugins\sqldrivers | 如果你单独安装了 Qt SDK,这里也会被扫描 |
提示:
qsqlmysql.dll必须放在上述任意一个sqldrivers目录下,且文件名必须是qsqlmysql.dll(Windows)、libqsqlmysql.so(Linux)或libqsqlmysql.dylib(macOS)。Qt 不会识别mysql.dll或qsql_mysql.dll这样的变体。
我曾见过一个项目,开发者把qsqlmysql.dll放在了./libs/目录下,然后在代码里调用QApplication.addLibraryPath("./libs")。这完全无效——addLibraryPath()添加的是 Qt 插件的根目录(即包含sqldrivers、imageformats等子目录的父目录),而不是sqldrivers本身。正确做法是QApplication.addLibraryPath("./libs/plugins"),前提是./libs/plugins/sqldrivers/下有qsqlmysql.dll。
2.2 qsqlmysql.dll:Qt 的 MySQL 驱动桥接器
qsqlmysql.dll本身并不实现 MySQL 协议,它只是一个轻量级的“胶水层”,负责将 Qt 的QSqlDriver接口调用,翻译成对底层 MySQL C API 的调用。因此,它必须链接(link)到真正的 MySQL 客户端库——libmysql.dll(Windows)或libmysqlclient.so(Linux)。
这个链接关系是静态链接还是动态链接,取决于你使用的 PyQt5 版本和构建方式:
- 官方 pip wheel(如 PyQt5-5.15.19):
qsqlmysql.dll是动态链接到libmysql.dll的。这意味着它在运行时必须能找到libmysql.dll,否则加载失败。 - conda 安装的 PyQt5:通常会把
libmysql.dll打包进 conda 环境的Library\bin目录,并通过修改PATH环境变量确保其可见。 - 从源码编译的 PyQt5:你可以选择静态链接(
--static参数),这样qsqlmysql.dll就不再依赖外部libmysql.dll,但体积会增大,且无法热更新 MySQL 客户端。
验证qsqlmysql.dll是否动态链接libmysql.dll,最直接的方法是用Dependency Walker(Windows)或ldd(Linux)工具查看其导入表。在 Windows 上,右键qsqlmysql.dll→ “属性” → “详细信息”标签页,如果“产品名称”显示为 “PyQt5” 而非 “Qt Project”,基本可以确定它是 pip wheel 版本,需要libmysql.dll。
2.3 libmysql.dll:MySQL 客户端库的“命门”
libmysql.dll是 MySQL 官方提供的 C API 客户端库,所有基于 MySQL C API 的语言绑定(包括 Qt 的qsqlmysql.dll、Python 的pymysql底层、甚至某些 PHP 扩展)都依赖它。它的版本必须与你的 MySQL 服务器向后兼容,但不能跨大版本跳跃。
| MySQL 服务器版本 | 推荐的 libmysql.dll 版本 | 兼容性说明 |
|---|---|---|
| MySQL 5.7.x | MySQL 5.7.x 安装包自带的libmysql.dll | 最稳定,官方 wheel 默认链接此版本 |
| MySQL 8.0.x | MySQL 8.0.x 安装包自带的libmysql.dll | 必须使用 8.0.x 版本,5.7 的libmysql.dll无法连接 8.0+ 服务器(认证插件变更) |
| MySQL 8.4+ | MySQL 8.4.x 安装包自带的libmysql.dll | 新增了对 caching_sha2_password 的原生支持 |
注意:
libmysql.dll的位数(32/64)必须与qsqlmysql.dll和 Python 解释器完全一致。一个 64 位的qsqlmysql.dll去加载 32 位的libmysql.dll,结果必然是ERROR_BAD_EXE_FORMAT,而 Qt 会将其统一包装为Driver not loaded。
最常见的错误场景是:你装了 MySQL 8.0.33 的 64 位 MSI 安装包,它把libmysql.dll放在了C:\Program Files\MySQL\MySQL Server 8.0\lib目录下。但这个目录不在系统 PATH 中,Qt 加载器找不到它。于是你手动把libmysql.dll复制到C:\Windows\System32(64 位系统)或C:\Windows\SysWOW64(32 位系统),以为万事大吉。结果发现,qsqlmysql.dll依然报错。为什么?因为libmysql.dll自身还有依赖!它需要VCRUNTIME140.dll、MSVCP140.dll(Visual C++ 2015-2019 运行库)等。如果你的机器没装 VC++ 运行库,或者版本太旧,libmysql.dll本身就加载失败,qsqlmysql.dll自然也跟着失败。
2.4 完整加载链路图:一个都不能少
我们可以把整个加载过程画成一条线性依赖链:
Python 脚本 → PyQt5 (qsqlmysql.dll) → Qt 插件加载器 → 扫描 sqldrivers 目录 → 找到 qsqlmysql.dll → → 加载 qsqlmysql.dll → qsqlmysql.dll 尝试加载 libmysql.dll → → libmysql.dll 加载成功 → qsqlmysql.dll 初始化完成 → QSqlDatabase.open() 成功只要其中任何一个环节断裂,最终呈现给用户的,都是同一个结果:Driver not loaded。而 Qt 并不会告诉你断在哪一环。所以,排查必须从最末端开始,逐级向上验证。
3. 四步精准排查法:从 DLL 存在性到运行时依赖的完整验证
面对Driver not loaded,网上充斥着“重装 PyQt5”、“重装 MySQL”、“把 dll 复制到 system32”等粗暴方案。这些方法偶尔奏效,但更多时候是碰运气,且无法复现、无法解释。下面是我总结的四步精准排查法,每一步都有明确的验证手段和预期结果,能帮你 100% 定位问题根源。
3.1 第一步:确认 qsqlmysql.dll 是否真实存在且路径正确
这是最基础也最容易被忽略的一步。很多人以为pip install PyQt5就自动配置好了所有驱动,其实不然。
操作步骤:
打开 Python 解释器,运行:
from PyQt5.QtSql import QSqlDatabase import os print("PyQt5 Qt plugins path:", os.path.dirname(QSqlDatabase.__file__) + "/../../../Qt5/plugins")这会输出类似
C:\Python39\Lib\site-packages\PyQt5\Qt5\plugins的路径。进入该路径下的
sqldrivers子目录(即C:\Python39\Lib\site-packages\PyQt5\Qt5\plugins\sqldrivers),检查是否存在qsqlmysql.dll文件。如果不存在,说明你安装的 PyQt5 wheel不包含 MySQL 驱动。官方 pip wheel 从 5.15.0 开始,默认只包含
qsqlite.dll和qsqlodbc.dll,MySQL 和 PostgreSQL 驱动需要额外安装。
解决方案:
方案 A(推荐):安装
PyQt5-tools,它通常会附带完整的驱动集:pip install PyQt5-tools安装后,
qsqlmysql.dll会出现在PyQt5-tools\Qt\plugins\sqldrivers目录下,你需要手动复制到PyQt5\Qt5\plugins\sqldrivers。方案 B:使用 conda 安装,conda-forge 的 PyQt5 包默认包含所有驱动:
conda install -c conda-forge pyqt方案 C:从 Qt 官网下载对应版本的 Qt MinGW 或 MSVC 安装包,提取
qsqlmysql.dll。但要注意,Qt 官方库的qsqlmysql.dll是为 Qt Creator 编译的,可能与 PyQt5 的 ABI 不兼容,风险较高,不推荐新手尝试。
提示:不要试图从网上随便下载一个
qsqlmysql.dll。不同 Qt 版本、不同编译器(MSVC vs MinGW)、不同架构(x64 vs x86)生成的 DLL 完全不兼容。我曾见过一个项目,开发者从 Qt 5.12 的安装包里拷贝了qsqlmysql.dll到 PyQt5 5.15 的目录下,结果程序启动时直接崩溃,因为 Qt 5.15 的QSqlDriver类内存布局已改变。
3.2 第二步:验证 qsqlmysql.dll 能否被 Qt 正确加载(排除路径和权限问题)
即使qsqlmysql.dll文件存在,Qt 也可能因权限或路径问题无法加载它。我们需要绕过 Python,用 Qt 自带的工具直接测试。
操作步骤:
- 下载并安装 Qt Creator (免费开源版即可)。
- 打开 Qt Creator,新建一个空的 Qt Widgets Application 项目。
- 在
main.cpp的main()函数开头,添加以下代码:#include <QSqlDatabase> #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication::addLibraryPath("C:/your/path/to/sqldrivers"); // 替换为你的 sqldrivers 目录绝对路径 qDebug() << "Available drivers:" << QSqlDatabase::drivers(); return 0; } - 编译并运行该项目。观察输出窗口。
预期结果与分析:
- 如果输出中包含
"QMYSQL",说明qsqlmysql.dll路径正确,Qt 能成功加载它。问题一定出在libmysql.dll或其依赖上。 - 如果输出是空列表
[]或只有["QSQLITE", "QODBC"],说明 Qt 根本没找到qsqlmysql.dll。请检查:addLibraryPath()中的路径是否拼写正确,是否是绝对路径。sqldrivers目录下是否真的有qsqlmysql.dll(注意大小写,Windows 不敏感,但 Linux/macOS 敏感)。- 该目录是否有读取权限(尤其在企业域环境下,有时策略会限制访问)。
注意:
QSqlDatabase::drivers()返回的是 Qt成功加载的驱动列表,不是磁盘上存在的文件列表。这是区分“文件存在”和“驱动可用”的黄金标准。
3.3 第三步:诊断 libmysql.dll 的加载状态(核心难点)
这是整个排查过程中最关键的一步,也是绝大多数人卡住的地方。我们需要确认qsqlmysql.dll是否能顺利加载libmysql.dll,以及libmysql.dll自身是否健康。
操作步骤(Windows):
- 下载 Process Monitor (微软官方免费工具)。
- 启动 Process Monitor,点击工具栏上的Filter → Filter...。
- 添加过滤规则:
Process Nameispython.exe(或你的 exe 文件名)OperationisCreateFilePathcontainslibmysql- 点击Add,然后OK。
- 运行你的 Python 脚本(或打包后的 exe)。
- Process Monitor 会捕获所有
CreateFile操作。在结果列表中,查找所有libmysql.dll的尝试记录。
关键观察点:
- 查找
Result列为NAME NOT FOUND的行。这表示 Qt 尝试在某个路径下寻找libmysql.dll,但没找到。记录下这些路径,它们就是 Qt 的搜索路径。 - 查找
Result列为SUCCESS的行。这表示libmysql.dll被找到了,但后续可能因依赖缺失而加载失败。 - 查找
Result列为PATH NOT FOUND或ACCESS DENIED的行。这表示路径本身不存在,或权限不足。
如果看到大量NAME NOT FOUND:说明libmysql.dll不在 Qt 的搜索路径中。你需要将libmysql.dll放到其中一个被搜索的路径下,最稳妥的是放到qsqlmysql.dll所在的sqldrivers目录里(同级),或者放到你的 Python 脚本/EXE 所在目录。
如果看到SUCCESS但程序仍报错:说明libmysql.dll被找到了,但它自身加载失败。这时需要用 Dependencies 工具打开libmysql.dll,查看其“Missing”依赖项。常见缺失项是VCRUNTIME140.dll、MSVCP140.dll、api-ms-win-crt-*.dll等。解决方案是安装 Microsoft Visual C++ 2015-2022 Redistributable 。
3.4 第四步:终极验证——用最小化 C++ 程序直连 MySQL
如果前三步都没发现问题,或者你想彻底排除 Python/PyQt5 层面的干扰,可以用一个极简的 C++ 程序来验证整个 MySQL 连接链路是否通畅。
创建test_mysql.cpp:
#include <QApplication> #include <QSqlDatabase> #include <QSqlError> #include <QDebug> int main(int argc, char *argv[]) { QApplication app(argc, argv); QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("localhost"); db.setPort(3306); db.setDatabaseName("mysql"); // 连接 mysql 系统库做测试 db.setUserName("root"); db.setPassword("your_password"); if (db.open()) { qDebug() << "Success! Connected to MySQL."; qDebug() << "Driver version:" << db.driver()->metaObject()->className(); db.close(); } else { qDebug() << "Failed:" << db.lastError().text(); } return 0; }编译与运行:
- 如果你有 Qt Creator,新建一个 Qt Console Application,粘贴以上代码,编译运行。
- 如果没有,可以使用
qmake和mingw32-make(需安装 Qt MinGW 工具链)。
结果解读:
- 如果 C++ 程序能成功连接,说明问题100% 出在你的 Python 环境或 PyQt5 安装上。可能是 Python 脚本路径、虚拟环境隔离、或 PyQt5 版本与 Qt 版本不匹配。
- 如果 C++ 程序也报
Driver not loaded,说明问题出在系统级的 Qt 插件或 MySQL 客户端库配置上,与 Python 无关。此时应重点检查PATH环境变量、libmysql.dll的位数匹配、以及 VC++ 运行库。
这四步法,每一步都提供了可量化的验证手段,避免了“我觉得应该没问题”的主观判断。我在客户现场处理过数十个同类案例,90% 的问题都能在第三步(Process Monitor)中定位到具体的libmysql.dll搜索路径缺失。
4. 生产环境部署方案:让驱动加载“永不掉链子”
开发机上跑通了,不代表生产环境也能跑通。用户电脑五花八门:有的装了多个 MySQL 版本,有的禁用了系统目录写入,有的用的是国产操作系统。我们必须设计一套鲁棒的部署方案,让qsqlmysql.dll和libmysql.dll的加载变得“傻瓜式”。
4.1 方案一:PyInstaller 打包时内嵌驱动(最推荐)
这是目前最成熟、最可控的方案。核心思想是:把所有依赖的 DLL 文件,和你的 Python 脚本一起打包进一个独立的 exe,让 Qt 的插件加载器永远能在./sqldrivers目录下找到它们。
操作步骤:
确保你的项目目录结构如下:
myapp/ ├── main.py ├── sqldrivers/ # 手动创建的目录 │ ├── qsqlmysql.dll # 从 PyQt5 安装目录拷贝 │ └── libmysql.dll # 从 MySQL 安装目录拷贝(必须与 MySQL 服务器版本匹配) └── ...使用 PyInstaller 打包时,显式指定
--add-data参数:pyinstaller --onefile --add-data "sqldrivers;sqldrivers" main.py注意:
--add-data的格式是"源路径;目标路径",Windows 下用分号;分隔,Linux/macOS 用冒号:。sqldrivers是目标路径,PyInstaller 会自动在生成的 exe 解压目录下创建sqldrivers子目录,并把源文件复制进去。在
main.py的开头,强制添加插件路径:import sys import os from PyQt5.QtWidgets import QApplication from PyQt5.QtSql import QSqlDatabase # 获取 exe 解压后的临时目录(PyInstaller 专用) if getattr(sys, 'frozen', False): # 打包后的 exe base_path = sys._MEIPASS else: # 直接运行 .py 文件 base_path = os.path.dirname(os.path.abspath(__file__)) # 将 sqldrivers 目录加入 Qt 插件搜索路径 plugin_path = os.path.join(base_path, 'sqldrivers') QApplication.addLibraryPath(plugin_path) # 现在再创建数据库连接 db = QSqlDatabase.addDatabase("QMYSQL") # ... rest of your code
优势:
- 完全自包含,不依赖用户电脑上的任何环境变量或已安装软件。
qsqlmysql.dll和libmysql.dll的版本、位数、依赖关系由你完全掌控。- 用户双击 exe 即可运行,零配置。
注意事项:
libmysql.dll必须从你目标 MySQL 服务器版本的安装目录中提取。例如,你要连接 MySQL 8.0.33,就必须用 8.0.33 安装包里的libmysql.dll。- 如果你的应用需要连接不同版本的 MySQL(如同时支持 5.7 和 8.0),你需要在
sqldrivers目录下放两个不同版本的libmysql.dll,并用代码逻辑在运行时切换。但这会极大增加复杂度,强烈建议统一后端 MySQL 版本。
4.2 方案二:环境变量注入法(适合企业内网统一部署)
如果你的软件是部署在公司内网,所有电脑都由 IT 部门统一管理,那么可以通过组策略或登录脚本,统一设置PATH环境变量,让libmysql.dll对所有进程可见。
操作步骤:
- 将
libmysql.dll(以及VCRUNTIME140.dll等依赖)集中存放在一个网络共享目录,如\\server\mysql_libs\8.0.33\。 - 创建一个批处理脚本
set_mysql_path.bat:@echo off setx PATH "%PATH%;\\server\mysql_libs\8.0.33" /M echo MySQL client library path added to system PATH. pause - 通过域组策略,将此脚本设置为“计算机配置 → 策略 → Windows 设置 → 脚本(启动/关机)→ 启动”脚本。
优势:
- 一次配置,全局生效,维护成本低。
libmysql.dll更新时,只需替换共享目录下的文件,所有客户端自动生效。
劣势:
- 需要管理员权限,普通用户无法执行。
setx /M会修改系统级 PATH,可能与其他软件冲突。- 不适用于面向公众的独立软件分发。
4.3 方案三:运行时动态解压 DLL(高级技巧)
对于极致的便携性要求(如 U 盘绿色软件),可以将qsqlmysql.dll和libmysql.dll以二进制形式嵌入 Python 源码,程序启动时动态解压到临时目录,并设置QApplication.addLibraryPath()。
核心代码片段:
import tempfile import os import atexit from PyQt5.QtWidgets import QApplication # 嵌入的 DLL 数据(此处为示意,实际需用 base64 或其他方式编码) QSQLMYSQL_DLL_DATA = b'...' # 你的 qsqlmysql.dll 的二进制内容 LIBMYSQL_DLL_DATA = b'...' # 你的 libmysql.dll 的二进制内容 def setup_qt_plugins(): # 创建临时目录 temp_dir = tempfile.mkdtemp() # 解压 DLL 到临时目录 qsql_path = os.path.join(temp_dir, 'sqldrivers', 'qsqlmysql.dll') libmysql_path = os.path.join(temp_dir, 'sqldrivers', 'libmysql.dll') os.makedirs(os.path.dirname(qsql_path), exist_ok=True) with open(qsql_path, 'wb') as f: f.write(QSQLMYSQL_DLL_DATA) with open(libmysql_path, 'wb') as f: f.write(LIBMYSQL_DLL_DATA) # 注册插件路径 QApplication.addLibraryPath(temp_dir) # 程序退出时清理临时文件 def cleanup(): import shutil shutil.rmtree(temp_dir, ignore_errors=True) atexit.register(cleanup) # 在 QApplication 创建前调用 setup_qt_plugins() app = QApplication(sys.argv)优势:
- 真正的单文件分发,无需额外的 DLL 文件。
- 完全规避了文件系统权限问题。
劣势:
- 增加了源码体积和编译复杂度。
- 每次启动都要解压,略微增加启动时间。
- 需要处理 anti-virus 软件对临时文件的误报(部分杀软会拦截动态解压行为)。
无论选择哪种方案,核心原则不变:让qsqlmysql.dll和libmysql.dll的物理位置、版本、位数、依赖关系,全部处于你的掌控之中。不要寄希望于“用户电脑上恰好有”,那是运维噩梦的开始。
5. 避坑指南:那些让你多花三天却毫无收获的“伪解决方案”
在解决Driver not loaded的过程中,我见过太多开发者在错误的方向上狂奔。他们花了大量时间尝试各种“网上教程”,结果不仅没解决问题,还把原本正常的环境搞坏了。以下是几个最典型的“伪解决方案”,以及为什么它们是陷阱。
5.1 陷阱一:“重装 PyQt5 就能好”
这是最普遍的误区。很多人看到报错,第一反应就是pip uninstall PyQt5 && pip install PyQt5。但问题在于:pip install PyQt5安装的是一个 wheel 包,它包含了编译好的qsqlmysql.dll,但这个 DLL 的构建环境(编译器版本、Qt 版本、链接的libmysql.dll版本)是固定的。重装只是重新下载同一个 wheel,不会改变任何东西。
为什么无效?
- 如果你原来装的就是
PyQt5-5.15.19,重装后还是5.15.19,qsqlmysql.dll还是那个链接了 MySQL 5.7libmysql.dll的 DLL。 - 如果你的 MySQL 是 8.0,问题依旧。
- 更糟的是,重装可能覆盖掉你之前手动放置的
qsqlmysql.dll,导致问题从“驱动加载失败”变成“驱动根本不存在”。
正确做法:
- 先确认你用的是哪个 PyQt5 版本:
pip show PyQt5。 - 查看该版本的 wheel 是否包含 MySQL 驱动:去 PyPI 页面 ,下载对应的
.whl文件,用7-Zip打开,检查PyQt5/Qt5/plugins/sqldrivers/目录下是否有qsqlmysql.dll。 - 如果没有,不要重装,而是按上文“四步排查法”中的方案 A,安装
PyQt5-tools并手动复制。
5.2 陷阱二:“把 libmysql.dll 复制到 C:\Windows\System32”
这是一个流传甚广的“土办法”。它的逻辑是:“System32 是系统目录,放这里肯定能找到”。但现代 Windows(Vista 及以后)引入了文件系统重定向(File System Redirector)和注册表重定向(Registry Redirector),使得 32 位程序在 64 位 Windows 上运行时,对System32的访问会被自动重定向到SysWOW64。
后果:
- 你的 Python 是 64 位,
libmysql.dll是 64 位,你把它复制到了C:\Windows\System32。 - Qt 加载器在 64 位进程中搜索
System32,找到了libmysql.dll,一切正常。 - 但你的同事用的是 32 位 Python,他的 Qt 加载器在 32 位进程中搜索
System32,结果被重定向到了C:\Windows\SysWOW64,而那里并没有libmysql.dll,于是报错。
更隐蔽的问题:
System32目录受 Windows Defender 和 UAC 保护,普通用户没有写入权限。强行复制可能导致权限错误。- 很多安全软件会监控
System32的写入行为,将其视为恶意活动。
正确做法:
- 永远不要往
System32或SysWOW64里放第三方 DLL。 - 把
libmysql.dll放在你的应用目录下,或sqldrivers目录下,这是最干净、最可控的方式。
5.3 陷阱三:“用 pymysql 替代 QSqlDatabase”
有些开发者被Driver not loaded折磨太久,干脆放弃QSqlDatabase,转而用pymysql直接操作数据库,然后把查询结果手动塞进QTableView。这看似解决了问题,实则埋下了更大的隐患。
为什么是倒退?
QSqlDatabase是 Qt 的一部分,它提供了与QSqlTableModel、QSqlQueryModel、QSqlRelationalTableModel等模型的无缝集成。这些模型能自动处理排序、过滤、编辑、提交,极大简化 UI 层的数据绑定逻辑。- 用
pymysql,你得自己写 CRUD 的 SQL 语句,自己处理事务,自己实现数据缓存和同步,自己处理并发修改冲突。工作量呈指数级增长。 QSqlDatabase支持异步查询(QSqlQuery::exec()是同步的,但你可以用QThread封装),而pymysql的阻塞式 IO 会让 UI 卡死,除非你手动做线程管理。
正确思路:
Driver not loaded是一个环境配置问题,不是架构问题。- 花一天时间彻底解决它,换来的是未来几个月的开发效率提升。
- 如果实在无法解决,那说明你的技术选型有问题——要么换用 SQLite(
QSQLITE驱动是内置的,永不报错),要么换用PySide6(它对 MySQL 驱动的支持更友好,且社区活跃度更高)。
5.4 陷阱四:“升级到 PyQt6 或 PySide6 就一劳永逸”
PyQt6 和 PySide6 确实在驱动管理上做了改进,比如支持更灵活的插件路径、更好的错误提示。但升级本身就是一个巨大的工程。
现实挑战:
- PyQt5 和 PyQt6 的 API 有显著差异:
QApplication.exec_()变成了QApplication.exec(),QFileDialog.getOpenFileName()的返回值元组结构变了,QPainter的绘图 API 也有调整。 - 如果你的项目有几万行代码,升级不是改几个 import 语句那么简单,而是一场全面