- Fix
Pool.wait_closed()blocking forever when the last connection was released while inside a transaction or after disconnecting, and notify pool waiters when a pool-fillingconnect()raises (#154).
- Set the PEP 249 module globals
apilevel,threadsafetyandparamstyle, and export the exception classes fromasyncmy(#77). - Expose the server's SQLSTATE on exceptions as
MySQLError.sqlstate;argsis unchanged (#138). - Fix
ssl=Truesilently connecting in plaintext: it now builds a default TLS context, and an ssl argument that is neitherTrue, a dict, nor anssl.SSLContextraisesValueErrorinstead of disabling TLS (#90). Connection.cursor()is now awaitable, so aiomysql'scur = await conn.cursor()spelling works;conn.cursor()andasync with conn.cursor()are unaffected (#145).- Add
Gtid.__hash__/GtidSet.__hash__— defining__eq__had madeGtidunhashable, which madeGtidSet(and therefore GTID replication) unusable (#59). - Declare the Cython modules free-threading compatible. Without this, importing asyncmy
re-enables the GIL for the whole process on a free-threaded build. Module-level state is built
during import and read-only afterwards; this does not make a single
Connection/Cursorsafe to share between threads. Requires Cython 3.1+, and CI now runs the suite on 3.14t. Thanks @honglei (#151). - Read the version from the installed package metadata instead of repeating it in
asyncmy/version.py, sopyproject.tomlis the single source and the_client_versionthe server sees cannot drift. Thanks @waketzheng (#149). - Ship type information (PEP 561):
py.typedplus.pyistubs for the Cython modules, so mypy and Pylance see real signatures instead of nothing.make stubsregenerates them andmake checkrunsstubtest, which fails on any drift from the compiled modules (#78). - Add
connect(password_creator=...): a callable consulted before every connection attempt, including the ones a pool makes when it recycles or reconnects, so short-lived credentials such as AWS RDS IAM tokens can be refreshed. May return an awaitable. Thanks @DolevGabay (#139). - Fix
ping(reconnect=True)never actually reconnecting:_connectedstayed set when the ping failed, soconnect()returned early and the follow-up ping ran on the dead connection. - Add
connect(query_callback=...), called ascallback(cursor, query, elapsed_ms)after every statement. Lets statement logging go somewhere other thanecho's hardcoded INFO line — a slow-query log, a tracing span, a different level.executemany/callprocreport once per call. Independent ofecho, which is unchanged (#81, #69). - Add
connect(sock=...): speak MySQL over a socket the caller has already connected. Combined withsslthe TLS handshake runs before the MySQL handshake instead of being negotiated in-protocol, which is what connectors fronting the server with a TLS proxy need (#71). - Mark the connection secure after the TLS handshake.
_securewas only set for unix sockets, socaching_sha2_passwordfull authentication over TLS took the RSA branch instead of sending the password in the clear, and the server rejected it with1045 Access denied(#117).
- Add server-side prepared statements (binary protocol):
stmt = await conn.prepare(sql),await stmt.execute(args). Parameters are sent in binary form (no client-side escaping) and results are parsed from the binary protocol — no text parsing for numeric/temporal columns. Large scans are ~35% faster than the text protocol; on the cross-language benchmark asyncmy's binary scan is now the fastest, ahead of go-sql-driver and mysql_async. - Add transparent statement cache:
connect(stmt_cache_size=N)makes plaincursor.execute("... %s ...", args)run as cached server-side prepared statements (binary protocol) with silent text-protocol fallback for unpreparable queries. Opt-in because FLOAT columns return the exact stored value under the binary protocol. - Replace StreamReader with a custom
asyncio.BufferedProtocol: incoming bytes land directly in the parse buffer (zero-copy receive, no per-read Future round-trips). - Cache prepared-statement column metadata: repeated executes skip re-parsing column definition packets entirely (C-level packet skipping).
- SSCursor now bulk-parses buffered rows (unbuffered scans ~10% faster on top of 0.2.12's 2.8x).
- DictCursor builds row dicts at C level.
- Fix
LOAD DATA LOCAL INFILEsending (awaiton a non-coroutine) and add write backpressure. - Build Linux aarch64 wheels.
- Negotiate
CLIENT_DEPRECATE_EOF: one packet less per result set and per prepare (both MySQL 5.7.5+ and MariaDB support it; legacy EOF path kept for older servers). - MariaDB: support
COM_STMT_BULK_EXECUTE—executemanybinds all rows in binary form in one round-trip whenstmt_cache_sizeis enabled (automatic text fallback); also available explicitly viastmt.execute_bulk(rows). - Fix
conftest.pyignoring a non-defaultMYSQL_PORT.
- Major performance improvement: buffered packet reading, C-level bulk row parsing, pointer-based protocol reads, direct cell decoding via CPython C-API, zero-decode numeric/temporal columns, escape fast path. Large result sets are 5-15x faster; asyncmy now ranks #1 in all benchmarks, details see benchmark/README.md.
- Fix
OKPacketWrapper.messagecontaining 2 stray bytes (read_struct position bug). - Fix
LoadLocalPacketWrappermissing attribute declarations (LOAD DATA LOCAL crash). - Fix potential integer overflow of
rowcount/insert_idon unbuffered cursors and Windows. - Benchmark suite now uses warmup + best-of-3 methodology.
- Security: remove unsafe
escape_dict— dict keys could reach SQL unescaped (CVE-2025-65896). (#134, #135, thanks @Cycloctane) - Fix
AttributeError: 'Connection' object has no attribute 'ssl'insha256_passwordauth branch. (#147, #148, thanks @shychee) - Support MySQL 8.0.19+
INSERT ... AS alias ON DUPLICATE KEY UPDATEsyntax inexecutemany. (#116, #120, thanks @MarkReedZ) - Pool closes idle/recycled connections with QUIT instead of aborting the TCP stream. (#112, #113, thanks @Cycloctane)
- Fix
OverflowErrorwhen escaping ints outside the signed 64-bit range, e.g. unsigned BIGINT2**64-1. (#35, #127) - Close connection when a query is cancelled mid-read to prevent stale results leaking into pooled reuse. (#107, #108)
- Use
setuptoolsinstead of deprecateddistutilsin build. (#106, thanks @tijuca)
- Fix
'Connection' object has no attribute '_auth_plugin_name'(#86)
- Fix ssl context pass bool.
- Fix missing
*.whlfor Python 3.12 (#94) - Fix SSL handshake error with MySQL server v8.0.34+. (#80)
- Added support for SSL context creation via
sslparameter using a dictionary containingmysql_ssl_setparameters. ( #64) - Fix bug with fallback encoder in the
escape_item()function. (#65)
- Fix sudden loss of float precision. (#56)
- Fix pool
echoparameter not apply to create connection. (#62) - Fix replication reconnect.
- Fix
No module named 'asyncmy.connection'.
- Fix raise_mysql_exception (#28)
- Implement
read_timeoutand removewrite_timeoutparameters (#44)
- Revert
TIMEreturndatetime.timeobject. (#37)
- Fix
escape_stringfor enum type. (#30) TIMEreturndatetime.timeobject.
- Fix
escape_sequence. (#20) - Fix
connection.autocommit. (#21) - Fix
_clear_result. (#22)
- Fix bug. (#18)
- Fix replication error.
- Fix
binlogstreamawait. (#12) - Remove
loopargument. (#15) - Fix
unix_socketconnect. (#17)
- Fix
cursor.close.
- Force int
pool_recycle. - Fix
echooption. - Fix bug replication and now don't need to connect manual.
- Fix pool recycle. (#4)
- Fix async
fetchone,fetchall, andfetchmany. (#7)
- Fix negative pk. (#2)
- Bug fix.
- Remove
byte2intandint2byte. - Fix warning for sql_mode.
- Add replication support.
- Fix pool.
- Fix build error.
- Fix build error.
- Release first version.