Library / SDK
aio-libs/aiomysql avatar
aio-libs/aiomysql

aiomysql is PyMySQL with await in front, and the SQLAlchemy extra is stuck on 1.3

aiomysql is a library for accessing a MySQL database from the asyncio

1,896 stars275 forksPythonMIT

At a glance

What is it?
The asyncio MySQL driver reuses PyMySQL wholesale and switches the IO calls to async, which is why its API looks familiar and why its SQLAlchemy layer carries a constraint that has quietly stopped matching modern releases. It also classifies itself as alpha while shipping releases.
Who is it for?
Adopt aiomysql if you have an asyncio service that must talk to MySQL and you value the PyMySQL familiarity, because the API is PyMySQL's with await added, the pool and cursor lifetimes are context managers, and you get MariaDB as well since the project keywords list both.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The whole driver is PyMySQL with the IO calls made async

The readme is unusually candid about how this is built. It says the library depends on and reuses most parts of PyMySQL, that internally it is a copy of PyMySQL with the underlying IO calls switched to async, with yield from and the asyncio coroutine decorator added in the appropriate places, and that the SQLAlchemy support was ported from aiopg. Copy rather than wrap is the important word. When the driver is a fork, you inherit the tested protocol implementation, the escaping rules and the type coercion, and you also inherit the maintenance model of a fork, which means protocol changes and security fixes have to be pulled in manually by whoever maintains the fork. The stated goal is to be like the aiopg library and preserve the same API, look and feel, which explains the shape of everything below. The user-facing consequence is stated too: since it is based on PyMySQL and provides the same API, you just need to await a call or yield from it instead of calling it, for every method. Properties are unchanged, so reading and assigning them works the same way. If you know PyMySQL you already know this driver, and that is the main argument for it.

Three nested context managers, which is the pooling model

The basic example nests three async with blocks, and each level corresponds to a lifetime you control.

python
async def test_example():
    async with aiomysql.create_pool(host='127.0.0.1', port=3306,
                                    user='root', password='',
                                    db='mysql') as pool:
        async with pool.acquire() as conn:
            async with conn.cursor() as cur:
                await cur.execute("SELECT 42;")
                (r,) = await cur.fetchone()

The outer one creates a pool and closes it on exit, so the pool is a resource you own for the life of your service rather than something created per request. The middle one acquires a connection from the pool and returns it on exit, which is the standard pattern: acquire, use, release. The inner one creates a cursor and closes it on exit. Inside that, a statement is executed with await, the cursor description is printed, and a single row is fetched and unpacked. Three things are worth drawing out. First, a cursor is a context manager, so the read habit of closing it explicitly is enforced by the structure rather than by discipline. Second, the pool is the reason this library is worth using at all in a server, because creating a MySQL connection per request is slow enough to dominate latency. Third, the acquire block is a mutex against pool exhaustion: if the pool has a maximum size and more coroutines want connections than exist, the excess waits at that line, and that back-pressure is often the thing that keeps a service alive under load. The examples directory has a dedicated pool example and separate old-style examples, which is a hint that both calling conventions are supported and that you will see both in the wild.

The SQLAlchemy extra is the constraint to read before you install

The optional dependency group for the SQLAlchemy integration is declared as sqlalchemy greater than or equal to 1.3 and less than 1.4. That is the whole story and it is a hard ceiling, not a preference. SQLAlchemy 2.0 has been the current major line for a long time, and an application on 2.0 cannot satisfy a bound that ends at 1.4, so this extra is effectively unusable in a modern project unless you are on an older SQLAlchemy yourself. The example shows what the layer looks like when it works: an engine is created with connection settings, a connection is acquired, statements are built from a table definition with insert and select, rows are iterated asynchronously, and the engine is closed and then waited on. That shape is familiar to anyone who used the aiopg equivalent, which is exactly what the readme says the port was based on. The question to ask is not whether the layer is well built but whether you are willing to hold your ORM at a version that predates the async SQLAlchemy work, because if you already depend on SQLAlchemy for other databases, the extra will collide with that dependency rather than complement it. A driver-only integration, using the pool and cursors directly, has no such problem, and for many services that is the cheaper path anyway.

What the examples folder says about the surface area

The examples are the best available feature list, and they come in pairs. There is a simple example, a cursors example, a pool example, an executemany example, a stored procedure example in both a new and an old calling style, a transaction example in both styles, an SSL example, and two SQLAlchemy examples in both styles. The duplication is the interesting part. Each of the substantive examples exists twice, once with the modern await style and once old-style, and the old-style files are named with an oldstyle suffix. That means both calling conventions are deliberately maintained and tested, which is generous to anyone maintaining older code and a signal that the project has not decided which convention it prefers. The coverage of the list is also worth noting: SSL is a first-class example rather than an afterthought, executemany and stored procedures are both exercised, and transactions are demonstrated. If you need one of those three things and you are choosing between async MySQL drivers, this is evidence that they are implemented rather than merely importable. What the list does not include is anything about connection retries, failover or reconnection after a server restart, which are the behaviours a long-running service actually needs and the ones the readme does not discuss.

Testing runs against a containerised MySQL 8.4

The development setup is straightforward and tells you what the project tests against. A compose file defines a MySQL service on the 8.4 image, with a named user, a password, a database called after the upstream test suite, and a root password, publishing the standard port. It also mounts a directory from the host into the socket location, which is how the test suite reaches the server over a Unix socket as well as over TCP, so both connection paths are covered. The makefile wraps the container lifecycle in a start and a stop target and prints the credentials it used, and the test, verbose test and coverage targets all depend on a flake8 check that itself depends on a strict packaging metadata check, so lint failures stop the tests. The coverage target writes both a terminal report and an HTML one. The repository also carries a pre-commit configuration, a coverage configuration for the reporting service, a flake8 configuration, a documentation build target, and separate requirement files for development and for documentation. A development container configuration is absent here, unlike the sibling asyncio projects, and the makefile carries two comments noting that documentation builds depend on the package being installed in the environment first. It is a mature, slightly old-fashioned contributor setup, and the test gate is strict.

Alpha status, irregular releases, and what to pin

The status classifier in the project metadata is development status 3, alpha, and the version is 0.3.2. Alpha at that version number is a long-standing state rather than a recent demotion, but it is still the project's own statement and it should shape how you adopt it. The release history explains the rhythm: 0.1.1 in May 2022, 0.2.0 in June 2023, and 0.3.2 in October 2025, so roughly annual with a long gap before the most recent. The last push to the main branch was on 2026-03-27, which is six months before the date this was written, so commits continue while releases do not, and the gap between the two is the number to plan around. If you depend on this, pin a version rather than tracking the branch, and expect that picking up a new release is an event rather than a routine. The build uses a version-control-based versioning plugin, so the version in your environment comes from the repository state at build time rather than from a hand-edited string, which is the right approach and another reason not to install from a checkout without a tag. The licence is MIT, and the project is POSIX only in its packaging metadata, which excludes Windows as a supported target.

Editorial conclusion

Adopt aiomysql if you have an asyncio service that must talk to MySQL and you value the PyMySQL familiarity, because the API is PyMySQL's with await added, the pool and cursor lifetimes are context managers, and you get MariaDB as well since the project keywords list both. Do not adopt it if you need a current SQLAlchemy, because the sa extra is bounded below 1.4 and the project classifies itself as alpha, and note the version picture before you pin: 0.3.2 was released on 2025-10-22 after a long gap, and the last push was on 2026-03-27, so the cadence is irregular. Four things to verify. That the SQLAlchemy extra version bound matches your application, because that is the most likely thing to block an install. That your PyMySQL version is new enough, since the manifest requires 1.0 or later and the driver reuses most of it. That you are on Python 3.9 or newer, which is the stated floor, and note the classifier list stops at 3.13. And whether you need RSA authentication, which is a separate extra built on the PyMySQL RSA support. The licence is MIT.

Frequently asked questions

What is the difference between aiomysql and PyMySQL?

aiomysql is a copy of PyMySQL with the underlying IO calls switched to async, so you await or yield from every method instead of calling it. Properties are unchanged, and the manifest declares PyMySQL 1.0 or later as its only required dependency.

Does aiomysql support SQLAlchemy?

There is an optional sa extra, and its support was ported from aiopg. The declared bound is SQLAlchemy greater than or equal to 1.3 and less than 1.4, so it will not install alongside a current SQLAlchemy 2.0 application.

How do I use an aiomysql connection pool?

Create the pool with the connection settings as an async context manager, then acquire a connection from it with another async with block, then open a cursor with a third. Each block releases its resource on exit, and the acquire block provides back-pressure when the pool is exhausted.

What are the requirements for aiomysql?

Python 3.9 or newer and PyMySQL. There is an extra for SQLAlchemy and an extra for RSA authentication built on the PyMySQL RSA support. The packaging metadata lists the platform as POSIX only.

What is the latest aiomysql release?

Version 0.3.2, released on 2025-10-22, after 0.2.0 in 2023 and 0.1.1 in 2022. The project classifies itself as development status 3, alpha, and the last push to the main branch was on 2026-03-27.

Official sources

  1. aio-libs/aiomysql on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/aio-libs-aiomysql.svg)](https://hysenlabs.com/projects/aio-libs-aiomysql)