| Crates.io | mariadb_exporter |
| lib.rs | mariadb_exporter |
| version | 0.5.0 |
| created_at | 2025-11-24 22:51:59.075997+00 |
| updated_at | 2025-12-15 09:55:58.362685+00 |
| description | MariaDB metric exporter for Prometheus |
| homepage | |
| repository | https://github.com/nbari/mariadb_exporter |
| max_upload_size | |
| id | 1948861 |
| size | 877,925 |
MariaDB metrics exporter for Prometheus written in Rust.
mysqld_exporter (prefixed mariadb_).Install via Cargo:
cargo install mariadb_exporter
Best practice: Use Unix socket with dedicated user
Create the exporter user with minimal privileges:
-- Create user for local socket connection only with connection limit
CREATE USER 'exporter'@'localhost' IDENTIFIED BY '' WITH MAX_USER_CONNECTIONS 3;
-- Grant minimal required permissions for all collectors
GRANT SELECT, PROCESS, REPLICATION CLIENT ON *.* TO 'exporter'@'localhost';
FLUSH PRIVILEGES;
Run the exporter:
mariadb_exporter --dsn "mysql:///mysql?socket=/var/run/mysqld/mysqld.sock&user=exporter"
Why this is secure:
localhost only (no network access)For remote monitoring or testing:
mariadb_exporter --dsn "mysql://exporter:password@host:3306/mysql"
Create user for network access:
CREATE USER 'exporter'@'%' IDENTIFIED BY 'strong_password_here' WITH MAX_USER_CONNECTIONS 3;
GRANT SELECT, PROCESS, REPLICATION CLIENT ON *.* TO 'exporter'@'%';
FLUSH PRIVILEGES;
mysql:///mysql?socket=/var/run/mysqld/mysqld.sock&user=exportermysql://user:password@host:3306/databasemysql://user:password@host/mysql?ssl-mode=REQUIREDmysql://user:password@host/mysql?ssl-mode=VERIFY_IDENTITY&ssl-ca=/path/to/ca.pemDefault port is 9306:
mariadb_exporter --dsn "..." --port 9187
Collectors are toggled with --collector.<name> or --no-collector.<name>.
--collector.default (enabled) – Core status (uptime, threads, connections, traffic), InnoDB basics, replication basics, binlog stats, config flags, version, mariadb_up, audit log enabled status.--collector.exporter (enabled) – Exporter self-metrics (process, scrape, cardinality).--collector.innodb – Advanced InnoDB metrics from SHOW ENGINE INNODB STATUS: LSN tracking, checkpoint age, active transactions, semaphore waits, adaptive hash index stats.--collector.tls – TLS session + cipher info.--collector.query_response_time – Buckets from query_response_time plugin.--collector.statements – Statement digest summaries/top latency from performance_schema.--collector.schema – Table size/row estimates (largest 20 non-system tables).--collector.replication – Relay log size/pos, binlog file count.--collector.locks – Metadata/table lock waits from performance_schema.--collector.metadata – metadata_lock_info table counts.--collector.userstat – Per-user stats (requires @@userstat=1 and USER_STATISTICS).defaultexporterEverything else is opt-in.
To enable all collectors for maximum visibility:
mariadb_exporter \
--dsn "mysql:///mysql?socket=/var/run/mysqld/mysqld.sock&user=exporter" \
--collector.default \
--collector.exporter \
--collector.innodb \
--collector.tls \
--collector.query_response_time \
--collector.statements \
--collector.schema \
--collector.replication \
--collector.locks \
--collector.metadata \
--collector.userstat
Or using environment variables:
export MARIADB_EXPORTER_DSN="mysql:///mysql?socket=/var/run/mysqld/mysqld.sock&user=exporter"
export MARIADB_EXPORTER_PORT="9306"
mariadb_exporter \
--collector.default \
--collector.exporter \
--collector.innodb \
--collector.tls \
--collector.query_response_time \
--collector.statements \
--collector.schema \
--collector.replication \
--collector.locks \
--collector.metadata \
--collector.userstat
Note: Some collectors require additional privileges or database configuration:
innodb – Requires PROCESS privilege (included in recommended setup)tls – Only shows data if TLS/SSL is enabledquery_response_time – Requires query_response_time plugin enabledstatements – Requires performance_schema enabledschema – Queries information_schema (can be slow on large databases)locks, metadata – Require performance_schema enableduserstat – Requires @@userstat=1 and USER_STATISTICS enabledThe --collector.innodb provides deep visibility into InnoDB internals by parsing SHOW ENGINE INNODB STATUS:
Metrics exposed:
mariadb_innodb_lsn_current – Current log sequence numbermariadb_innodb_lsn_flushed – LSN flushed to diskmariadb_innodb_lsn_checkpoint – Last checkpoint LSNmariadb_innodb_checkpoint_age_bytes – Uncheckpointed bytes (LSN current - checkpoint)mariadb_innodb_active_transactions – Count of active InnoDB transactionsmariadb_innodb_semaphore_waits_total – Semaphore wait events (internal contention)mariadb_innodb_semaphore_wait_time_ms_total – Total semaphore wait timemariadb_innodb_adaptive_hash_searches_total – Adaptive hash index hitsmariadb_innodb_adaptive_hash_searches_btree_total – AHI misses requiring B-tree lookupUse cases:
Requirements:
PROCESS privilege (for SHOW ENGINE INNODB STATUS)Enable with:
mariadb_exporter --collector.default --collector.innodb
mariadb_exporter
├── bin
├── cli
├── collectors
│ ├── config.rs
│ ├── default
│ ├── exporter
│ ├── innodb
│ ├── locks
│ ├── metadata
│ ├── mod.rs
│ ├── query_response_time
│ ├── register_macro.rs
│ ├── registry.rs
│ ├── replication
│ ├── schema
│ ├── statements
│ ├── tls
│ ├── userstat
│ └── util.rs
└── src/lib.rs
Each collector lives in its own subdirectory for clarity and easy extension.
Run tests:
cargo test
Run with container-backed integration (requires podman):
just test
Test with Unix socket connection (production-like setup):
# Test with combined MariaDB + exporter container (most realistic)
just test-socket
Lint:
cargo clippy --all-targets --all-features
For detailed information on testing with Unix socket connections, see TESTING_SOCKET.md.
Quick start:
# Test with combined MariaDB + exporter container (most realistic)
just test-socket
The project follows a modular collector architecture:
mariadb_exporter/
├── bin/ # Binary entry point
├── cli/ # CLI argument parsing
├── collectors/ # All metric collectors
│ ├── mod.rs # Collector trait and registration
│ ├── registry.rs # Collector orchestration
│ ├── config.rs # Collector enable/disable logic
│ └── */ # Individual collector modules
└── exporter/ # HTTP server (Axum)
src/collectors/ with a mod.rsCollector trait:
register_metrics(&self, registry: &Registry) - Register Prometheus metricscollect(&self, pool: &MySqlPool) - Fetch data and update metrics (async)enabled_by_default(&self) - Whether collector runs by defaultregister_collectors! macro in src/collectors/mod.rs:
register_collectors! {
// ... existing collectors ...
your_collector => YourCollector,
}
The macro automatically generates all registration boilerplate.
This project enforces strict clippy lints (see Cargo.toml):
unwrap_used, expect_used, panic, indexing_slicing, await_holding_lock? for error propagation, never .unwrap() or .expect().get() instead of [index] for slicing.ok() instead of .unwrap()Exceptions are allowed only in test code with #[allow(clippy::unwrap_used)].
# Run unit tests
cargo test
# Run with container integration
just test
# Lint (must pass)
cargo clippy --all-targets --all-features
# Validate Grafana dashboard
just validate-dashboard
When adding metrics to the Grafana dashboard:
$job, $instance)just validate-dashboardSee grafana/README.md for detailed dashboard documentation.
cargo testcargo clippy --all-targets --all-featuresjust validate-dashboardSET GLOBAL userstat=ON; (or @@userstat=1) to expose userstat metrics.metadata_lock_info plugin for the metadata collector.