MY

MySQL Server Exporter

Official Prometheus exporter for MySQL and MariaDB

Monitoring & Status ★ 2.5k stars Easy setup Apache-2.0

MySQL Server Exporter is the official Prometheus exporter for MySQL and MariaDB servers, exposing global status, replication, InnoDB, and performance schema metrics. It is a standard component of database monitoring stacks built on Prometheus.

Key features

  • Global status and InnoDB metrics
  • Replication lag tracking
  • Performance schema collectors
  • Officially maintained by Prometheus

Pros & cons

Strengths

  • Reliable and well-tested
  • Granular collector toggles

Trade-offs

  • Metrics only, no visualization
  • Some collectors add load

MySQL Server Exporter replaces

Last reviewed Sep 13, 2026 · 840 words

The mistake almost everyone makes with mysqld_exporter is connecting it as root. The exporter needs exactly three privileges, PROCESS, REPLICATION CLIENT and SELECT, and it should be capped at 3 connections so a scrape storm cannot exhaust the pool that your actual application depends on. Get the user right and the rest of this 64 MB Go binary is scrape it and forget it. It is the official Prometheus project exporter, 2,461 stars, Apache-2.0, and around since 2015, which is why every MySQL dashboard on the internet assumes its metric names.

Create the user before you start the container

Run this on the MySQL or MariaDB server, adjusting the host to wherever the exporter connects from:

CREATE USER 'exporter'@'%' IDENTIFIED BY 'a-long-password'
  WITH MAX_USER_CONNECTIONS 3;
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%';
FLUSH PRIVILEGES;

The MAX_USER_CONNECTIONS 3 clause is the important line. Prometheus retries a slow scrape, and without the cap a database that is already struggling gets extra exporter connections piling on. With it, the worst case is a failed scrape and an alert, which is what you want.

Credentials go in a my.cnf-style file rather than an environment variable. At last check the newer releases dropped the old DATA_SOURCE_NAME environment variable entirely, so if you are following a 2020-era tutorial and the exporter refuses to start, that is why.

[client]
user = exporter
password = a-long-password
host = db
port = 3306

Mount it and point the flag at it:

services:
  mysqld-exporter:
    image: prom/mysqld-exporter:latest
    command: ["--config.my-cnf=/etc/mysqld-exporter/my.cnf"]
    volumes:
      - ./my.cnf:/etc/mysqld-exporter/my.cnf:ro
    ports:
      - "9104:9104"
    restart: unless-stopped

Port 9104 is the convention; curl localhost:9104/metrics should return a few hundred lines starting with mysql_global_status_. Then add a job to Prometheus with that target and you are collecting.

Collectors: the defaults are safe, the extras are not free

The exporter's job is running SHOW GLOBAL STATUS, SHOW GLOBAL VARIABLES, reading information_schema and, optionally, performance_schema. The default set is cheap. The optional collectors are where the catalogue's "some collectors add load" warning applies.

CollectorDefaultCost on the database
global_status, global_variablesonnegligible
slave_status (replication lag)onnegligible
info_schema.innodb_metricsonlow
info_schema.tablesoffone query per table, painful past a few thousand tables
perf_schema.eventsstatementsoffmoderate, and needs performance_schema enabled
info_schema.processlistofflow, but exposes query text in labels
auto_increment.columnsoffscans every table's schema

Turn extras on one at a time with --collect.info_schema.tables and similar flags, then watch the exporter's own mysql_exporter_collector_duration_seconds metric. If any collector takes more than a second on a 15-second scrape interval, turn it off or lengthen the interval for that job. On a homelab MariaDB behind Nextcloud or a WordPress install, the defaults plus info_schema.tables are all I ever enable.

The three metrics that predict trouble

Most of what the exporter emits is noise until something breaks. Three are worth an alert rule from day one. mysql_global_status_threads_connected against mysql_global_variables_max_connections tells you when a connection leak is about to take the site down; alert at 80%. mysql_global_status_innodb_buffer_pool_reads rising fast relative to innodb_buffer_pool_read_requests means the working set no longer fits in RAM, which is the cheapest performance fix in existence. And mysql_slave_status_seconds_behind_master above 30 on a replica means your read replica is serving stale data.

The mysql_up gauge is the exporter's own health; it drops to 0 when the credentials are wrong or the server is unreachable, and it is the first thing to check when a dashboard goes blank.

Grafana makes it worth the trouble

Raw metrics are only useful with a dashboard, and the exporter emits none of its own. Import Percona's MySQL Overview dashboard into Grafana, which is built for exactly these metric names and shows QPS, connections, buffer pool hit rate, and replication lag on one screen. If you are new to the pairing, the Grafana vs Prometheus explainer settles the "which one do I need" confusion: both, one stores, one draws.

Run the exporter as a sidecar next to each database rather than one central exporter for all of them. A central exporter is possible with the multi-target /probe endpoint, but it means one set of credentials with reach into every server and one process whose failure blanks every dashboard.

What I'd do

Dedicated exporter user with the three grants and a 3-connection cap, credentials in a mounted my.cnf, default collectors only, scrape every 30 seconds. Two alert rules: connections above 80% of max for 5 minutes and mysql_up == 0 for 2 minutes. Percona's overview dashboard in Grafana. That is a 20-minute job that has caught every MySQL problem I have had before a user did. If you run PostgreSQL instead, the same recipe applies with the postgres exporter, and the wider monitoring category has the node and container exporters that complete the picture.

Similar monitoring & status apps