How to Connect to MariaDB from C# (.NET)

5 min readMariaDB

MariaDB speaks the MySQL wire protocol, so connecting from C# uses the same drivers you would use for MySQL. There is no separate "MariaDB .NET driver" worth reaching for; the practical choice is between two MySQL-compatible ADO.NET drivers, and one of them is the clear default for new code.

Driver choice

MySqlConnector (2.6.1 as of June 2026) is the recommended driver. It is a clean-room, async-first ADO.NET implementation under the MIT license, and it explicitly supports MariaDB alongside MySQL, Aurora, Azure Database for MySQL, and Percona. Its async methods are genuinely asynchronous, which matters under load.

MySql.Data (Oracle's official Connector/NET, 9.7.0 as of June 2026) also connects to MariaDB, but its history of sync-over-async implementations makes it a weaker pick for high-concurrency services. If you are starting fresh, use MySqlConnector. The two share most of the API but live in different namespaces, so you cannot mix them in the same file without aliasing.

dotnet add package MySqlConnector

A basic connection

using MySqlConnector;
 
var connString =
    "Server=localhost;Port=3306;Database=shop;" +
    "User ID=appuser;Password=secret;";
 
await using var conn = new MySqlConnection(connString);
await conn.OpenAsync();

await using ensures the connection is returned to the pool when the scope exits. Do not hold one connection open for the life of the app; open per unit of work and let pooling do its job (more below).

Running a query

await using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT id, name FROM products WHERE price > @minPrice";
cmd.Parameters.AddWithValue("@minPrice", 100);
 
await using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
    var id = reader.GetInt32(0);
    var name = reader.GetString(1);
    Console.WriteLine($"{id}: {name}");
}

Always parameterize. String-concatenating user input into SQL is the classic injection hole, and the driver's parameters also handle quoting and type conversion for you.

Getting a generated key

MariaDB does not have SQL Server's OUTPUT clause or PostgreSQL's RETURNING in the same form (MariaDB does support RETURNING on INSERT since 10.5, which is a genuine option). The ADO.NET-portable way is LastInsertedId:

await using var cmd = conn.CreateCommand();
cmd.CommandText = "INSERT INTO products (name, price) VALUES (@name, @price)";
cmd.Parameters.AddWithValue("@name", "Widget");
cmd.Parameters.AddWithValue("@price", 9.99m);
await cmd.ExecuteNonQueryAsync();
 
long newId = cmd.LastInsertedId;

If you prefer RETURNING, run it as a normal query and read the result set back, but be aware it ties your code to MariaDB 10.5+ and breaks portability to MySQL.

The utf8mb4 trap

MariaDB's legacy utf8 is a three-byte encoding that cannot store emoji or some CJK characters. Use utf8mb4 for the column charset, and the driver handles the rest. If you see Incorrect string value on insert, this is almost always the cause:

ALTER TABLE products MODIFY name VARCHAR(255)
  CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Authentication differences from MySQL

This is where MariaDB and MySQL diverge in a way that matters. MySQL 8 defaults to the caching_sha2_password auth plugin; MariaDB does not use it. MariaDB sticks with mysql_native_password and adds its own ed25519 plugin for stronger auth. So the caching_sha2_password and "Public Key Retrieval" headaches that plague MySQL 8 connections do not apply to MariaDB. If you want stronger-than-native auth on MariaDB, ed25519 is the path, and MySqlConnector supports it.

Connection pooling

Pooling is on by default and keyed by the connection string. The defaults worth knowing:

  • Maximum Pool Size defaults to 100.
  • Minimum Pool Size defaults to 0.
  • Connection Idle Timeout defaults to 180 seconds.

The number you actually need to coordinate is total pool size across all app instances versus MariaDB's max_connections (default 151). Five app instances each with a 100-connection pool can demand 500 connections against a server that allows 151, and you get Too many connections under load. Size pools to fit the server, or raise max_connections deliberately.

Dapper

MySqlConnector is a standard ADO.NET provider, so Dapper (2.1.79 as of June 2026) works directly:

using Dapper;
 
var products = await conn.QueryAsync<Product>(
    "SELECT id, name, price FROM products WHERE price > @minPrice",
    new { minPrice = 100 });

Entity Framework Core

For EF Core, use the Pomelo provider, Pomelo.EntityFrameworkCore.MySql (9.0.0 as of June 2026), which targets both MySQL and MariaDB and builds on MySqlConnector. Declare the server version so the provider enables the right feature set:

var serverVersion = ServerVersion.AutoDetect(connString);
 
builder.Services.AddDbContext<AppDb>(options =>
    options.UseMySql(connString, serverVersion));

ServerVersion.AutoDetect opens a connection at startup to read the server version; if you want to avoid that round trip, pass an explicit MariaDbServerVersion(new Version(11, 4, 0)).

SSL

For connections over an untrusted network, set the SSL mode:

SSL ModeBehavior
NoneNo encryption
PreferredEncrypt if the server supports it (default)
RequiredEncrypt, but do not validate the server certificate
VerifyCAEncrypt and validate the CA
VerifyFullEncrypt, validate CA and hostname

Use VerifyFull for production connections over a public network. Required encrypts but leaves you open to man-in-the-middle, so it is not enough on its own.

var connString =
    "Server=db.example.com;Database=shop;User ID=appuser;Password=secret;" +
    "SSL Mode=VerifyFull;";

Errors you actually hit

SymptomCauseFix
Too many connectionsCombined pool size exceeds max_connectionsReduce Maximum Pool Size or raise server max_connections
Incorrect string valueColumn is legacy utf8, not utf8mb4Convert column/table charset to utf8mb4
Access denied for userWrong host pattern on the grantMariaDB grants are user@host; check the host part matches your client
Unable to connect to any of the specified hostsWrong host/port or server not listeningVerify bind-address, port 3306, firewall
Time values off by hoursServer and client time zones differStore UTC; convert in app code, not in SQL

For exploring MariaDB data and drafting queries before they go into C#, Mako connects to MariaDB with AI-powered autocomplete. Try it free at mako.ai.

Mako — open source

Skip the terminal. Use Mako.

Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.