How to Connect to MariaDB from Java
Java connects to MariaDB through JDBC, and you have two realistic choices: MariaDB's own Connector/J (org.mariadb.jdbc:mariadb-java-client), or MySQL's Connector/J pointed at the MariaDB server. They both work for routine queries because MariaDB began as a MySQL fork and speaks a compatible wire protocol. This guide uses the official MariaDB driver, explains when the MySQL driver is fine, and covers pooling, authentication, and the MariaDB-specific features worth knowing.
Which driver
MariaDB Connector/J is a Type 4 (pure Java) driver built specifically for MariaDB and MySQL servers. Use it when you connect to MariaDB. The MySQL Connector/J will also connect to a MariaDB server for basic SQL, but it is built and tested against MySQL, and newer MySQL-server features baked into its defaults (authentication plugins, metadata behavior) do not always line up with MariaDB. If your target is MariaDB, the native driver is the lower-surprise choice.
Maven:
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.5.9</version>
</dependency>Gradle:
implementation 'org.mariadb.jdbc:mariadb-java-client:3.5.9'Connector/J 3.5 is a JDBC 4.2/4.3-era driver and requires Java 8 or higher (as of June 2026). It self-registers, so Class.forName("org.mariadb.jdbc.Driver") is not needed.
The basic connection
The JDBC URL scheme is jdbc:mariadb://, not jdbc:mysql://:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class Example {
public static void main(String[] args) throws Exception {
String url = "jdbc:mariadb://localhost:3306/mydb";
String user = "app_user";
String password = "secret";
try (Connection conn = DriverManager.getConnection(url, user, password)) {
String sql = "SELECT id, email FROM users WHERE created_at > ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, java.time.LocalDate.of(2026, 1, 1));
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getLong("id") + " " + rs.getString("email"));
}
}
}
}
}
}Use ? positional placeholders with PreparedStatement. That parameterizes the query safely and lets the server cache the plan.
Character set
Create your database and tables with utf8mb4 so the full Unicode range (including emoji and many CJK characters) round-trips correctly. The legacy utf8 alias in the MySQL/MariaDB world is three-byte and silently truncates four-byte characters. This is a server/schema decision, but it surfaces as mangled data in Java, so it is worth checking before you blame the driver.
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Authentication plugins
MariaDB supports several authentication plugins. The two you are most likely to meet:
mysql_native_passwordis the traditional plugin and works out of the box.ed25519is MariaDB's own stronger plugin. Connector/J supports it natively, so no extra configuration is needed beyond having the user created with it on the server.
Note that MariaDB does not use MySQL 8's caching_sha2_password. This is one place where pointing the MySQL Connector/J at a MariaDB server can get awkward, and another reason to prefer the native driver against MariaDB.
RETURNING: get inserted rows back
MariaDB supports INSERT ... RETURNING (and DELETE ... RETURNING), which MySQL does not. Instead of doing an insert and then a separate SELECT LAST_INSERT_ID(), you can read the generated values directly:
String sql = "INSERT INTO users (email) VALUES (?) RETURNING id, created_at";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "new@example.com");
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
System.out.println("new id " + rs.getLong("id"));
}
}
}Because this returns a result set, run it with executeQuery() rather than executeUpdate(). This is genuinely useful for getting auto-generated IDs and defaults in one round trip.
Connection pooling with HikariCP
Open one pool per application and reuse connections. Do not call DriverManager.getConnection per request.
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mariadb://localhost:3306/mydb");
config.setUsername("app_user");
config.setPassword("secret");
config.setMaximumPoolSize(10);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
try (HikariDataSource ds = new HikariDataSource(config)) {
try (Connection conn = ds.getConnection()) {
// ...
}
}Connector/J also ships its own internal pool (enable with pool=true in the URL), but most Java stacks standardize on HikariCP, and Spring Boot uses it by default. Pick one pool, not both.
Size maximumPoolSize against the server's max_connections divided across all application instances. A pool of 10 per instance times 20 instances is 200 connections, which can exceed a default max_connections of 151 and produce Too many connections under load. Count instances before setting the number.
SSL/TLS
For a server requiring encryption, add sslMode:
String url = "jdbc:mariadb://db.example.com:3306/mydb?sslMode=verify-full";verify-full checks the certificate chain and hostname. Use it for production. trust encrypts but skips verification, which leaves you open to a man-in-the-middle and should be limited to local debugging. Point at a CA with serverSslCert when using a private CA.
Common errors
| Error | Cause |
|---|---|
Access denied for user | Wrong credentials, or user host pattern does not match the client |
Could not connect ... Connection refused | Server not listening on that host/port, or bind-address restricts it |
Too many connections | Pool size times instance count exceeds max_connections |
Public Key Retrieval is not allowed | You are using the MySQL driver against MariaDB with caching_sha2_password expectations; use the native driver |
| Garbled non-ASCII text | Schema is utf8 (3-byte) instead of utf8mb4 |
unsupported authentication method | Auth plugin mismatch; the native driver supports ed25519, the MySQL one does not |
Where Mako fits
When your Java service is talking to MariaDB, you usually want to inspect tables and prototype queries by hand. Mako connects to MariaDB with AI-powered autocomplete so you can explore the schema and write a query interactively before moving it into code. It is a read/query tool, not a schema-management or administration console. For bulk loading, see our import CSV to MariaDB guide.
Mako connects to MariaDB, MySQL, PostgreSQL, and more 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.