How to Connect to MariaDB from Python
MariaDB speaks the MySQL wire protocol, so you have an unusual choice: use MariaDB's own official connector, or use any of the MySQL drivers, which work fine against MariaDB. Plenty of production MariaDB deployments run on PyMySQL or mysqlclient and never touch the official connector. This guide covers when each choice makes sense, with working code for all of them.
The options
| Driver | Maintainer | Implementation | paramstyle | Version (as of June 2026) |
|---|---|---|---|---|
| mariadb (Connector/Python) | MariaDB | C extension over Connector/C | qmark (?) | 1.1.14 stable, 2.0 in RC |
| mysqlclient | PyMySQL org | C extension over libmysqlclient/Connector/C | format (%s) | 2.2.8 |
| PyMySQL | PyMySQL org | Pure Python | format (%s) | 1.2.0 |
| mysql-connector-python | Oracle | Pure Python (+ optional C) | format (%s) | 9.7.0 |
Rules of thumb:
- Greenfield MariaDB-only project: the official
mariadbconnector. It is the only driver that exposes MariaDB-specific capabilities directly and tracks MariaDB server releases. - Code that might run against MySQL too, or a team that already knows the MySQL drivers: mysqlclient (speed) or PyMySQL (zero build dependencies). Nothing breaks; you just write
%splaceholders instead of?. - Django: mysqlclient remains the documented default for MariaDB backends. Don't fight the framework.
The drivers are not drop-in compatible with each other -- the official connector uses ? placeholders (qmark) while every MySQL driver uses %s. Switching means touching every query. Pick once.
The official mariadb connector
The build dependency trap
Version 1.1 is a C extension that links against MariaDB Connector/C. On Windows, pip installs a prebuilt wheel. On Linux and macOS, there are no binary wheels for 1.1 -- pip compiles from source, which fails with a mariadb_config not found or Python.h: No such file or directory error unless the system packages are present:
# Debian/Ubuntu
sudo apt install libmariadb-dev python3-dev
pip install mariadb
# macOS
brew install mariadb-connector-c
pip install mariadbThis is the single most common installation failure, and it is the main reason teams quietly use PyMySQL instead. The upcoming 2.0 release fixes it: 2.0 (release candidate as of June 2026) is a ground-up rewrite distributed as pure Python with an optional C accelerator, installable via pip install mariadb[binary] with Connector/C bundled, and it adds native asyncio support. Until 2.0 goes stable, expect the apt/brew step on 1.1.
Connecting
import mariadb
conn = mariadb.connect(
host="localhost",
port=3306,
user="app",
password="secret",
database="shop",
)
cur = conn.cursor()
cur.execute("SELECT id, name FROM customers WHERE country = ?", ("CH",))
for row in cur:
print(row)
conn.close()Note the ? placeholder -- qmark style, like SQLite, unlike every MySQL driver. Tuples in, tuples out. cur.execute(sql, ("CH",)) needs the trailing comma for single parameters; passing a bare string is the classic mistake (each character becomes a parameter).
Autocommit is off by default, matching the DB API spec. Your INSERTs vanish on close unless you call conn.commit() or set conn.autocommit = True.
Connection pooling
Built in, no extra package:
pool = mariadb.ConnectionPool(
pool_name="app",
pool_size=5,
host="localhost",
user="app",
password="secret",
database="shop",
)
conn = pool.get_connection()
try:
cur = conn.cursor()
cur.execute("SELECT 1")
finally:
conn.close() # returns the connection to the poolMariaDB-specific: INSERT ... RETURNING
MariaDB 10.5+ supports RETURNING on INSERT (and DELETE since 10.0, REPLACE since 10.5) -- a feature MySQL does not have. Any driver can use it since it is just SQL, but it replaces the lastrowid dance cleanly:
cur.execute(
"INSERT INTO orders (customer_id, total) VALUES (?, ?) RETURNING id, created_at",
(42, 199.90),
)
order_id, created_at = cur.fetchone()Using the MySQL drivers against MariaDB
Everything in our MySQL from Python guide applies to MariaDB: same connection parameters, same %s placeholders, same utf8mb4 charset advice, same wait_timeout reconnection traps. A minimal PyMySQL example for completeness:
import pymysql
conn = pymysql.connect(
host="localhost",
user="app",
password="secret",
database="shop",
charset="utf8mb4",
cursorclass=pymysql.cursors.DictCursor,
)
with conn.cursor() as cur:
cur.execute("SELECT id, name FROM customers WHERE country = %s", ("CH",))
print(cur.fetchall())
conn.commit()Two MariaDB-vs-MySQL differences worth knowing when you reuse MySQL drivers:
- Authentication plugins. MySQL 8 defaults to
caching_sha2_password, which older drivers struggled with; MariaDB defaults tomysql_native_password(and offersed25519). Connecting to MariaDB therefore avoids the auth-plugin errors common with MySQL 8 -- but if you followed MySQL hardening guides that forcecaching_sha2_password, note MariaDB does not implement it. - Version strings. MariaDB reports versions like
11.8.3-MariaDB. Code that parses server versions (some ORMs, migration tools) occasionally misreads this. SQLAlchemy handles it via dedicatedmariadbdialect naming (below).
SQLAlchemy
SQLAlchemy 2.0 has explicit MariaDB-only dialect prefixes, which enable MariaDB-specific features (like INSERT...RETURNING support in the ORM) and refuse to connect to a MySQL server:
from sqlalchemy import create_engine
# Official mariadb connector
engine = create_engine("mariadb+mariadbconnector://app:secret@localhost/shop")
# Or via the MySQL drivers
engine = create_engine("mariadb+pymysql://app:secret@localhost/shop?charset=utf8mb4")Add pool_pre_ping=True if connections sit idle long enough to hit the server's wait_timeout.
Async
As of June 2026 the stable official connector (1.1) has no asyncio support -- that arrives with 2.0. Today your async options are the MySQL ecosystem drivers, which work against MariaDB: asyncmy (0.2.11, C-accelerated) or aiomysql (built on PyMySQL). Both use %s placeholders and integrate with SQLAlchemy's async engine (mariadb+asyncmy:// is not a registered dialect, so async SQLAlchemy users connect with the mysql+asyncmy:// prefix and lose the MariaDB-only dialect features).
Common errors
| Error | Cause |
|---|---|
mariadb_config not found / Python.h: No such file during pip install | Missing libmariadb-dev (or Connector/C) and python3-dev |
Commands out of sync | Unread result set; consume or use buffered cursors |
| Inserts silently missing | Autocommit off (DB API default), no conn.commit() |
Access denied for user 'app'@'172.x.x.x' | MariaDB accounts are user@host patterns; the Docker bridge IP needs its own grant or 'app'@'%' |
Server has gone away after idle | wait_timeout closed the connection; use pool_pre_ping, conn.ping(), or auto_reconnect |
Verifying your data
After connecting, you usually want to browse schemas and check rows landed. The mariadb CLI works; a GUI is faster -- we compared the options in Best MariaDB GUI Clients. For loading data, see Import CSV to MariaDB and Import Excel to MariaDB.
Mako connects to MariaDB with AI-powered autocomplete. Try it free at mako.ai.
Skip the terminal. Use Mako.
Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.