A high-performance async MySQL driver for Python, powered by Rust.
- High Performance: Rust core via mysql_async — fastest large result set processing of all Python MySQL drivers
- asyncmy-compatible API: Drop-in replacement — identical
connect()/create_pool()parameter names and defaults - Async/Await: Native asyncio support powered by Tokio
- Connection Pooling: Built-in pool with configurable size and TTL-based recycling
- Bulk Insert:
executemany()automatically collapses rows into a single multi-rowINSERT - Type Safety: Full type hints with
.pyistub files - DB-API 2.0 Compatible: Works with aiomysql and asyncmy patterns
pip install myrsqlimport asyncio
import myrsql
async def main():
conn = await myrsql.connect(
host="localhost",
user="root",
password="password",
database="test",
autocommit=True,
)
cursor = conn.cursor()
await cursor.execute("SELECT * FROM users WHERE id = %s", [1])
row = cursor.fetchone()
print(row)
await conn.close()
asyncio.run(main())import asyncio
import myrsql
async def main():
pool = await myrsql.create_pool(
host="localhost",
user="root",
password="password",
database="test",
minsize=5,
maxsize=20,
autocommit=True,
)
async with pool.acquire() as conn:
cursor = conn.cursor()
await cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
print(rows)
await pool.close()
asyncio.run(main())import asyncio
import myrsql
async def main():
conn = await myrsql.connect(
host="localhost",
user="root",
password="password",
database="test",
)
cursor = conn.cursor("DictCursor")
await cursor.execute("SELECT id, name, email FROM users")
for row in cursor:
print(f"ID: {row['id']}, Name: {row['name']}")
await conn.close()
asyncio.run(main())import asyncio
import myrsql
async def main():
conn = await myrsql.connect(
host="localhost",
user="root",
password="password",
database="test",
autocommit=True,
)
cursor = conn.cursor()
data = [(f"user_{i}", f"user_{i}@example.com") for i in range(10000)]
# Automatically compiled into a single multi-row INSERT — one round-trip
await cursor.executemany(
"INSERT INTO users (name, email) VALUES (%s, %s)",
data,
)
await conn.close()
asyncio.run(main())import asyncio
import myrsql
async def main():
conn = await myrsql.connect(
host="localhost",
user="root",
password="password",
database="test",
)
await conn.begin()
try:
cursor = conn.cursor()
await cursor.execute("INSERT INTO users (name) VALUES (%s)", ["Alice"])
await cursor.execute("INSERT INTO users (name) VALUES (%s)", ["Bob"])
await conn.commit()
except Exception:
await conn.rollback()
raise
await conn.close()
asyncio.run(main())Parameters mirror asyncmy's connect() for drop-in compatibility.
conn = await myrsql.connect(
host=None, # default: 127.0.0.1
port=0, # default: 3306
user=None,
password=None,
database=None,
db=None, # alias for database
unix_socket=None,
charset=None, # default: server default
sql_mode=None,
init_command=None,
connect_timeout=None, # default: 10 s
autocommit=False,
read_timeout=None,
# ... and all other asyncmy-compatible kwargs
)pool = await myrsql.create_pool(
minsize=1,
maxsize=10,
pool_recycle=3600, # max connection lifetime in seconds; -1 = disabled
echo=False,
# ... same connection kwargs as connect()
)Pool usage:
# Context manager (recommended — auto-returns connection to pool)
async with pool.acquire() as conn:
...
# Manual acquire / close
conn = await pool.acquire()
try:
...
finally:
await conn.close() # returns connection to pool| Class | Description |
|---|---|
Connection |
Database connection |
Pool |
Connection pool |
Cursor |
Query cursor — rows as tuples |
DictCursor |
Query cursor — rows as dict |
Transaction |
Transaction context manager |
DB-API 2.0 exception hierarchy:
Error— base classDatabaseError→InterfaceError/OperationalError/ProgrammingError/IntegrityError/DataError/NotSupportedError/InternalError
Comprehensive benchmark against all major Python MySQL drivers. Environment: local MySQL, Python 3.12, macOS.
| Rank | Library | Time | vs myrsql |
|---|---|---|---|
| 🏆 1 | myrsql | 0.082s | — |
| 2 | mysqlclient | 0.085s | –3% |
| 3 | asyncmy | 0.106s | –23% |
| 4 | pymysql | 0.145s | –44% |
| 5 | aiomysql | 0.150s | –45% |
myrsql is fastest overall — Rust row parsing beats both C and pure-Python drivers.
| Rank | Library | Time | Rows/sec |
|---|---|---|---|
| 1 | aiomysql | 0.102s | 98,405 |
| 🥈 2 | myrsql | 0.106s | 94,534 |
| 3 | mysqlclient | 0.108s | 92,404 |
| 4 | pymysql | 0.122s | 81,864 |
| 5 | asyncmy | 0.136s | 73,673 |
myrsql collapses all rows into a single
INSERT … VALUES (…),(…)query — one network round-trip regardless of row count.
| Rank | Library | Time | Queries/sec |
|---|---|---|---|
| 1 | asyncmy | 0.188s | 10,635 |
| 🥈 2 | myrsql | 0.205s | 9,756 |
| 3 | aiomysql | 0.246s | 8,129 |
myrsql beats aiomysql and is within 9% of asyncmy.
| Rank | Library | Time | Queries/sec |
|---|---|---|---|
| 1 | asyncmy | 0.013s | 3,910 |
| 2 | aiomysql | 0.013s | 3,719 |
| 3 | myrsql | 0.019s | 2,616 |
myrsql is ~50% slower here. The gap is architectural: every
awaitcrosses the Tokio ↔ asyncio thread boundary (GIL contention). Pure-Python async drivers have zero cross-thread overhead. For workloads that reuse pooled connections this cost is already amortized (see pool benchmark above).
uv sync
MYSQL_PASS=xxx uv run python -m benchmark.run_all- Rust 1.70+
- Python 3.9+
- uv (Python package manager)
# Clone the repository
git clone https://github.com/long2ice/myrsql.git
cd myrsql
# Install dependencies and build
uv sync
# Build the Rust extension
uv run maturin develop
# Run tests
uv run pytest# Format Python code
uv run ruff format .
# Lint Python code
uv run ruff check .
# Type check
uv run ty checkMIT License - see LICENSE for details.