Skip to content

nbari/mariadb_exporter

Repository files navigation

Test & Build codecov Crates.io License

mariadb_exporter

MariaDB metrics exporter for Prometheus written in Rust.

Features

  • Modular collectors – Enable only what you need; heavy/optional collectors stay off by default.
  • Compatibility – Metric names align with Prometheus mysqld_exporter (prefixed mariadb_).
  • Lean defaults – Essential availability, InnoDB, and replication metrics enabled by default; optional collectors opt-in.
  • Low footprint – Designed to minimize cardinality and avoid expensive scans.

Download or build

Install via Cargo:

cargo install mariadb_exporter

Usage

Recommended Setup (Secure)

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:

  • ✅ No password needed (socket authentication)
  • ✅ User restricted to localhost only (no network access)
  • ✅ Minimal privileges (read-only + monitoring)
  • ✅ Connection limit prevents resource exhaustion
  • ✅ No exposure to network attacks

Alternative: TCP Connection

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;

Common DSN Formats

  • Unix socket (recommended): mysql:///mysql?socket=/var/run/mysqld/mysqld.sock&user=exporter
  • TCP: mysql://user:password@host:3306/database
  • TLS required: mysql://user:password@host/mysql?ssl-mode=REQUIRED
  • TLS verify identity: mysql://user:password@host/mysql?ssl-mode=VERIFY_IDENTITY&ssl-ca=/path/to/ca.pem

Change Port

Default port is 9306:

mariadb_exporter --dsn "..." --port 9187

Available collectors

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.metadatametadata_lock_info table counts.
  • --collector.userstat – Per-user stats (requires @@userstat=1 and USER_STATISTICS).

Enabled by default

  • default
  • exporter

Everything else is opt-in.

Enable all collectors

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 enabled
  • query_response_time – Requires query_response_time plugin enabled
  • statements – Requires performance_schema enabled
  • schema – Queries information_schema (can be slow on large databases)
  • locks, metadata – Require performance_schema enabled
  • userstat – Requires @@userstat=1 and USER_STATISTICS enabled

InnoDB Advanced Metrics

The --collector.innodb provides deep visibility into InnoDB internals by parsing SHOW ENGINE INNODB STATUS:

Metrics exposed:

  • mariadb_innodb_lsn_current – Current log sequence number
  • mariadb_innodb_lsn_flushed – LSN flushed to disk
  • mariadb_innodb_lsn_checkpoint – Last checkpoint LSN
  • mariadb_innodb_checkpoint_age_bytes – Uncheckpointed bytes (LSN current - checkpoint)
  • mariadb_innodb_active_transactions – Count of active InnoDB transactions
  • mariadb_innodb_semaphore_waits_total – Semaphore wait events (internal contention)
  • mariadb_innodb_semaphore_wait_time_ms_total – Total semaphore wait time
  • mariadb_innodb_adaptive_hash_searches_total – Adaptive hash index hits
  • mariadb_innodb_adaptive_hash_searches_btree_total – AHI misses requiring B-tree lookup

Use cases:

  • Monitor checkpoint age to prevent log file overflow
  • Track LSN progression for write workload analysis
  • Detect long-running transactions
  • Identify internal InnoDB contention (semaphore waits)
  • Measure adaptive hash index efficiency

Requirements:

  • PROCESS privilege (for SHOW ENGINE INNODB STATUS)

Enable with:

mariadb_exporter --collector.default --collector.innodb

Project layout

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.

Testing

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

Socket Connection Testing

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

Developer Guidelines

Architecture

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)

Adding a New Collector

  1. Create a subdirectory under src/collectors/ with a mod.rs
  2. Define a struct implementing the Collector trait:
    • register_metrics(&self, registry: &Registry) - Register Prometheus metrics
    • collect(&self, pool: &MySqlPool) - Fetch data and update metrics (async)
    • enabled_by_default(&self) - Whether collector runs by default
  3. Add ONE line to register_collectors! macro in src/collectors/mod.rs:
    register_collectors! {
        // ... existing collectors ...
        your_collector => YourCollector,
    }

The macro automatically generates all registration boilerplate.

Strict Linting Rules

This project enforces strict clippy lints (see Cargo.toml):

  • DENY: unwrap_used, expect_used, panic, indexing_slicing, await_holding_lock
  • Use ? for error propagation, never .unwrap() or .expect()
  • Use .get() instead of [index] for slicing
  • Use pattern matching or .ok() instead of .unwrap()

Exceptions are allowed only in test code with #[allow(clippy::unwrap_used)].

Testing

# 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

Dashboard Development

When adding metrics to the Grafana dashboard:

  1. Ensure metrics are exported by collectors
  2. Add panels following existing structure (clean, professional, no emojis)
  3. Use template variables ($job, $instance)
  4. Add clear descriptions (Goal/Action format)
  5. Validate before committing: just validate-dashboard

See grafana/README.md for detailed dashboard documentation.

Commit Guidelines

  • Run tests before committing: cargo test
  • Run clippy: cargo clippy --all-targets --all-features
  • Validate dashboard if modified: just validate-dashboard
  • Keep commit messages clear and descriptive

Notes

  • User statistics: enable with SET GLOBAL userstat=ON; (or @@userstat=1) to expose userstat metrics.
  • Metadata locks: load metadata_lock_info plugin for the metadata collector.
  • Performance schema is needed for statements/locks collectors to return data.
  • Optional collectors skip gracefully when prerequisites aren't present.

About

A MariaDB metric exporter for Prometheus written in Rust

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages