Skill

MariaDB

mariadb · current version v1

Download v1

Troubleshoot and support a MariaDB server — connect, diagnose, and resolve problems across 10.6/10.11/11.x, on Docker, bare metal, systemd, a managed service, or Kubernetes. Covers the mariadb client (the mysql name is gone in 11.x), config paths, connections, InnoDB locks, slow queries, replication and Galera, and disk. Use when someone reports MariaDB is down, slow, refusing connections, a mysql command "not found", deadlocking, a Galera node not joining, or lagging a replica.

12 downloads · published 2026-09-02

What this grants

Skill Card

Security Audits

Version history

VersionPublishedStatus
v1 2026-09-02 published

Files

SKILL.md

raw | preview

---
name: mariadb
description: Troubleshoot and support a MariaDB server — connect, diagnose, and resolve problems across 10.6/10.11/11.x, on Docker, bare metal, systemd, a managed service, or Kubernetes. Covers the mariadb client (the mysql name is gone in 11.x), config paths, connections, InnoDB locks, slow queries, replication and Galera, and disk. Use when someone reports MariaDB is down, slow, refusing connections, a mysql command "not found", deadlocking, a Galera node not joining, or lagging a replica.
---

# MariaDB — Troubleshooting & Support

A support runbook, not a tutorial. Establish the host with the **detect-platform** skill first,
then work top to bottom: read before you write. Commands and output below were run against
MariaDB 11.8.9. MariaDB is a separate product from MySQL — the SQL and InnoDB overlap, but the
tooling, versions, replication (GTID differs), and clustering (Galera) do not. Confirm which you
are on before applying a MySQL runbook here.

Lines: **10.6** and **10.11** are long-term; **11.x** is current. Diagnose against `SELECT VERSION();`
(it prints e.g. `11.8.9-MariaDB`).

## 0. Identify what you are on — and the client-name trap

```bash
mariadb --version        # mariadb … 11.8.9-MariaDB … — the client is `mariadb`
mariadb -uroot -p -N -e 'SELECT VERSION();'
mariadbd --version       # the server binary is `mariadbd`
```
**The trap:** in current MariaDB the historical `mysql`/`mysqld` names are gone — verified in the
11.8 image, only `mariadb` and `mariadbd` exist, no `mysql` symlink. A runbook (or a monitoring
check) that calls `mysql`/`mysqld` fails with "command not found" on a modern MariaDB. Use
`mariadb`/`mariadbd`. Older packages still ship `mysql` as a compatibility symlink, so its
presence does not prove the server is MySQL — the version string does.

Config and data:
```bash
mariadb -uroot -p -e "SHOW VARIABLES WHERE Variable_name IN ('datadir','log_error','socket','port','bind_address');"
# Debian/Ubuntu: /etc/mysql/ (mariadb.conf.d/) ; RHEL: /etc/my.cnf.d/ ; upstream image: /etc/mysql/
```

## 1. Connect, per deployment

**Docker** — error log to stderr → `docker logs`:
```bash
docker exec -it <c> mariadb -uroot -p
docker logs --tail 200 -f <c>
```
**systemd (bare metal or VM)**:
```bash
systemctl status mariadb
journalctl -u mariadb -n 200 --no-pager
tail -f /var/log/mysql/error.log 2>/dev/null || tail -f /var/lib/mysql/*.err
```
**Bare metal** — the settings that bite (detect-platform gave RAM and any cgroup cap):
```bash
# innodb_buffer_pool_size ~50-70% of RAM on a dedicated host, but it MUST fit under a
# container/cgroup limit or mariadbd is OOM-killed.
mariadb -uroot -p -e "SELECT @@innodb_buffer_pool_size/1024/1024/1024 AS gb, @@max_connections;"
cat /proc/$(pgrep -o mariadbd)/limits | grep 'open files'
```
**Managed** — no host shell; client connects, config is the parameter group, restarts/failover via
the console. `SHOW`, the slow log, and status views still work.

**Kubernetes (operator)** — `kubectl exec -it <pod> -- mariadb -uroot -p`; config is the CR; the
root password is in a Secret.

## 2. Tools and arguments

```bash
mariadb -h <host> -P 3306 -u <user> -p -D <db>   # -N no header, -B tab-separated, -e "SQL" one-shot
mariadb-admin -uroot -p status                    # uptime/threads/questions (was mysqladmin)
mariadb-dump -uroot -p --single-transaction --routines --triggers <db> > db.sql   # was mysqldump
mariadb-binlog <binlog>                           # inspect/replay binlogs
```
The `mariadb-*` names replace the old `mysql*` tool names; on older installs the `mysqldump` etc.
names may still exist as symlinks.

## 3. Diagnostics — read-only first

```sql
SHOW GLOBAL STATUS LIKE 'Threads_connected';   SHOW VARIABLES LIKE 'max_connections';
SHOW FULL PROCESSLIST;                          -- connections, their Time and State
SHOW ENGINE INNODB STATUS\G                     -- LATEST DETECTED DEADLOCK, lock waits, buffer pool
SELECT * FROM information_schema.INNODB_LOCK_WAITS;   -- current blocking
```
Slow queries: `SET GLOBAL slow_query_log=ON; SET GLOBAL long_query_time=0.2;` then read the slow
log. MariaDB also has the slow-log analyzer `mariadb-dumpslow`. Plans: `EXPLAIN <query>;` and
`ANALYZE <query>;` (MariaDB's `ANALYZE` runs it and shows real vs estimated rows).

## 4. Common problems → resolution

**`mysql: command not found`** — you are on modern MariaDB; use `mariadb` (see §0). This is the
single most common "the runbook is wrong" ticket after a MySQL→MariaDB migration.

**Cannot connect**
- Socket path or down server: `Can't connect … socket '/run/mysqld/mysqld.sock'` — check the server
  is up and the `socket` variable, or force TCP with `-h 127.0.0.1`.
- Auth: MariaDB defaults to `mysql_native_password`/`ed25519`, **not** MySQL 8's
  `caching_sha2_password` — a driver configured for one against the other fails. `SELECT user, host,
  plugin FROM mysql.user;` shows what each account uses.
- `Too many connections` — `max_connections` reached; a pooler beats raising it.

**InnoDB locks / deadlocks** — same shape as MySQL: `SHOW ENGINE INNODB STATUS\G` for the latest
deadlock; find a stuck holder in `SHOW PROCESSLIST` and `KILL <id>` (§6); `Lock wait timeout
exceeded` points at a long/abandoned transaction.

**Galera cluster (if this is a Galera node)**
```sql
SHOW STATUS LIKE 'wsrep_cluster_size';     -- how many nodes are in the primary component
SHOW STATUS LIKE 'wsrep_local_state_comment';   -- Synced | Donor/Desynced | Joining | Initialized
SHOW STATUS LIKE 'wsrep_cluster_status';   -- Primary vs non-Primary (a partitioned node)
```
- A node stuck `Joining` is doing an SST (full state transfer) — watch the error log for the
  transfer method and disk/network. A `non-Primary` node lost quorum; do not force it Primary
  unless you are certain it holds the newest data (`wsrep_last_committed`), or you resurrect stale
  writes. Bootstrapping the cluster from the wrong node is the classic Galera data-loss event.

**Replication lag / broken**
```sql
SHOW REPLICA STATUS\G   -- Seconds_Behind_Source, Slave_IO/SQL_Running, Last_Error (SHOW SLAVE STATUS on old versions)
```
MariaDB GTID (`0-1-1234`) differs from MySQL GTID — do not mix the two servers in one topology
expecting compatible GTIDs.

**Disk filling / won't start** — same as MySQL: binlogs piling up (`SHOW BINARY LOGS;`,
`PURGE BINARY LOGS BEFORE …` once replicas consumed them, §6); per-table reclaim via
`OPTIMIZE TABLE` (locks); on a crash InnoDB recovers on start, and `innodb_force_recovery` is a
last resort that can lose data (§6).

## 5. Before you run anything that writes

`KILL`, `PURGE BINARY LOGS`, `OPTIMIZE TABLE`, `SET GLOBAL`, Galera bootstrap, and restarts change
data, availability, or config — on a nanoinfra deployment a `mutate.remote` capability (approval
interactively, a standing grant unattended). Name the node and the change.

- `SET GLOBAL` is runtime-only; persist in the config or a restart loses it.
- `KILL <id>` rolls back an in-flight write.
- On Galera, bootstrapping (`galera_new_cluster` / `--wsrep-new-cluster`) declares a node the source
  of truth for the whole cluster — pick the node with the latest committed state, never blindly.
- `PURGE BINARY LOGS`: confirm replicas consumed them first.
- `innodb_force_recovery > 0`: copy `datadir` first; use the lowest level that lets you dump and rebuild.