mysqlclient: the build probes four library names, and the README says not to ask for help
MySQL/MariaDB connector for Python
At a glance
- What is it?
- A GPL Python connector for MySQL and MariaDB, forked from a driver that predates Python 3, that reaches the database client library through the system compiler rather than shipping its own. Installing it means satisfying a package-query tool on the command line, the build probes four possible library names because two distributions disagree on the filename, and the most repeated instruction on the page is where not to ask for help.
- Who is it for?
- This is worth using if you want a database driver that links against the platform's own client library rather than implementing the wire protocol in Python, and you are comfortable with a source build. Three things decide whether it will install cleanly.
- Can I use it commercially?
- Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- PyMySQL/mysqlclient2,542 ★ · +6
| Repository | 2026-09-30 | 2026-11-14 |
|---|---|---|
| PyMySQL/mysqlclient | 2.5k | 2.5k |
6 Stars in the last 45 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The most repeated instruction is where not to ask for help
Three separate sections of the documentation tell you not to file an issue. The support section opens by saying not to use the issue tracker for help and adds that the maintainer is not free technical support, then routes questions by subject: a Python-shaped question goes to the Python mailing list or the Python Slack, a database-shaped one goes to the vendor support page or the MariaDB knowledge base. The Windows section says building there is very hard and, if a source build fails, says in bold not to come asking for support. The Linux section repeats it in a slightly different form, saying that an error you can see is yours to fix or to take to a forum, and to not file an issue. That is an unusual amount of repetition for a documentation page, and it is paired with a metadata classifier saying the project is production stable, so the two statements sit side by side. The one command the Linux section does give is the pair of package installs, one per distribution family:
$ sudo apt-get install python3-dev default-libmysqlclient-dev build-essential pkg-config # Debian / Ubuntu
$ % yum install python3-devel mysql-devel pkgconfig # Red Hat / CentOSNote that the two are not the same packages under different names: the Debian line installs the default MySQL client development package while the Red Hat line installs a differently named one, which is the same disagreement that makes the build probe four candidates.
Importing without the global lock does not make a connection thread-safe
There is a short section on free threading, and it makes a distinction that is easy to skim past. Since a recent release, importing the extension module is supported under free threading, so importing the driver does not acquire the global interpreter lock. That is stated first and plainly. Then it says the library still does not support simultaneous operations on a single connection object from multiple threads, regardless of free threading, and that behaviour in such cases remains undefined. A warning callout repeats it as a direct instruction: do not use a single connection object from several threads at once. The note is also marked as experimental. So the headline is a genuine improvement to import behaviour, and the headline does not change the thread-safety contract of the object people actually share between threads.
The build probes four library names because two distributions disagree
The build does not know what the client library on this machine is called, so it asks, in order, for four candidate names and uses the first one that exists. The comment above the list gives the reason directly: one Linux distribution ships the package file under one name and another family ships it under a different one. A build on the wrong guess produces link errors rather than a useful message, which is why the fallback list exists. If none of the four is found, the build raises an exception whose message tells you to set the compiler and linker flag variables by hand. The discovery itself is a subprocess call to the package-query tool with an existence check, and each attempt is printed as it goes, so the log shows exactly which name answered.
Two environment variables skip the discovery step, but only when both are set
The build reads two environment variables, one for compiler flags and one for linker flags, and the logic around them has a subtlety worth noting. Discovery is skipped only when both are set; if you supply just one, the build still goes and asks the package-query tool for a name, then fills in whichever flag you did not provide from that query. So a partial override is a valid configuration rather than an error, and a complete override removes the dependency on the tool entirely, which is what you want on a machine where the library is installed somewhere unusual or where the query tool is absent. The documentation gives the intended way to produce those two values, both obtained from the same query tool, and then installs the package as usual.
The static flag removes itself from the argument list before the build system sees it
One command-line flag is handled by rewriting the argument list. The build checks for a static flag among the arguments, sets an internal variable, and then removes that argument from the list before anything else runs. The variable then changes the query invocations by appending a static flag to them, so the discovered flags describe a statically linked client library. Removing the argument is necessary because the same list is handed to the packaging tool, which would reject an option it does not recognise. That is a tidy piece of engineering and a slightly surprising one to read, since a flag that appears in your command line disappears from every diagnostic about it. The same file also reads the version by executing the release module rather than importing it, so the version is available before the package is importable.
Windows needs one vendor's C connector, in its default directory
The Windows section is the shortest of the three platform sections and the most demanding. It states that building there is very hard, then points at binary wheels as the easy path, and then describes the source build: download the MariaDB C connector, install it, and have a Visual Studio version appropriate to your interpreter. The constraint that catches people is placement. The connector must be installed in its default location, and two paths are given, one for 64-bit and one for 32-bit. If you built the connector yourself or installed it elsewhere, an environment variable has to be set before installing to point at it. So there is a fourth environment variable in this project, and it exists only on this platform.
A make target called check rewrites your working tree
The build file has five targets, and one of them does not do what its name says. The check target runs the linter across the top-level scripts, the source tree and the continuous integration directory, and then runs the formatter across the same three paths. Neither invocation passes a verification flag, so both rewrite files in place. A target named check that modifies your working tree is a trap in a project with a good history, because it is exactly the command a contributor runs before committing and expects to be read-only. The same file builds the extension the old way, invoking the setup script directly with an in-place flag, even though the packaging metadata declares a modern build backend and a recent minimum version of it, and its documentation target installs the package and the documentation tool before building.
The requirements file exists for continuous integration, and there are two formatters
The development requirements file opens with a comment saying it is for the continuous integration action, and its four entries are the test runner, coverage tooling and a small library for pretty-printing tracebacks. That last one tells you the project's failure diagnosis is assertion-based rather than interactive. Everything else about development is in the tree instead: a linter configuration at the root, a separate formatter invoked by the same make target, a dependency update bot configuration, a coverage configuration, a security policy and an agent instruction file. The two formatters coexisting with a single configuration file is the other detail worth noting, since a project that runs a linter and then a formatter across the same paths has two opinions about the same lines and resolves it by letting the second one win.
Editorial conclusion
This is worth using if you want a database driver that links against the platform's own client library rather than implementing the wire protocol in Python, and you are comfortable with a source build. Three things decide whether it will install cleanly. Check whether a binary wheel exists for your interpreter version first, because every platform section exists only for the case where it does not. On Windows, budget for a source build, which means installing a specific vendor's C connector in its default location and pointing an environment variable at it if you put it elsewhere, and having a matching compiler. And note what the page is emphatic about: importing the extension without the global lock does not make a connection safe to share between threads, and the driver says twice not to do it.
Frequently asked questions
pymysql vs mysqlclient
This repository does not compare them. It lives under the same organisation but says nothing about the other project. What it states about itself is that it is a fork of an older driver to which Python 3 support and many bug fixes were added, that it links against the platform's client library through the system compiler rather than implementing the protocol, and that it is distributed under the GPL.
how to install mysqlclient in ubuntu
Install the development headers first, then let pip build the package. On Debian and Ubuntu the page gives one command covering the Python 3 development package, the default MySQL client development package, a compiler toolchain and the package-query tool; on Red Hat family distributions it gives the equivalent with different package names. After that a single pip install line finishes the job.
Does mysqlclient support free-threaded Python?
Importing the extension no longer acquires the global lock since a recent release, but the page marks that support experimental. It also states that a single connection object must not be used from several threads at once, regardless of free threading, and that behaviour in that case is undefined.
Why is mysqlclient hard to install on Windows?
The page says so plainly, and then tells you not to ask for support if it fails. Binary wheels exist for some interpreter versions. Otherwise you build from source, which needs the MariaDB C connector installed in its default location, or an environment variable pointing at it if you installed it elsewhere, plus a Visual Studio version matching your interpreter.
What does mysqlclient need to build on macOS?
The package-query tool, plus either the full database package or the client-only package. The client-only route additionally needs the package search path exported to the client library's pkgconfig directory before installing, and it avoids installing a database server you do not intend to run.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pymysql-mysqlclient)Star history chart for your README
[](https://hysenlabs.com/projects/pymysql-mysqlclient)Was this useful?