Grafana MySQL Monitoring

A slow database slows every application built on top of it. Watching connections, queries, and memory in real time reveals trouble early. This project connects a MySQL server to Prometheus through mysqld_exporter and builds a health dashboard in Grafana that any team member can read.

The Hospital Monitor Analogy

A hospital monitor tracks a patient's heart rate, blood pressure, and oxygen level in real time. Nurses react to trends, not just emergencies. A database dashboard tracks the equivalent vital signs: connections, query rate, slow queries, and buffer use. Early warning signs show up in the numbers long before a crash.

+--------+   SQL    +----------------+  metrics  +------------+
| MySQL  | <------- | mysqld_exporter| --------> | Prometheus |
+--------+          +----------------+  port 9104+-----+------+
                                                      |
                                                  +---v----+
                                                  | Grafana|
                                                  +--------+

Create a Monitoring User

The exporter needs a database account with limited rights. Never use the root account for monitoring.

CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'USE-A-STRONG-PASSWORD'
  WITH MAX_USER_CONNECTIONS 3;

GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';

Replace the sample password with a long random one, and store it in a secrets manager.

Run the Exporter

Create a small file that holds the credentials, so they stay out of the command line.

[client]
user=exporter
password=USE-A-STRONG-PASSWORD

Save it as .my.cnf with permissions that only the exporter user can read. Start the exporter.

./mysqld_exporter --config.my-cnf=.my.cnf

Open http://SERVER_IP:9104/metrics to confirm a list of metrics that begin with mysql_.

Add the Scrape Job

scrape_configs:
  - job_name: "mysql"
    static_configs:
      - targets: ["192.168.1.20:9104"]

Restart Prometheus and confirm the target shows UP.

Choose the Vital Signs

MetricPlain Meaning
mysql_up1 when the exporter reaches MySQL, 0 when it cannot
mysql_global_status_threads_connectedOpen client connections
mysql_global_variables_max_connectionsThe connection limit
mysql_global_status_queriesTotal queries, as a growing counter
mysql_global_status_slow_queriesQueries slower than the slow query limit
mysql_global_status_threads_runningQueries that execute right now

Build the Panels

Database Status

mysql_up

Use a stat panel with value mappings: 1 shows "Online" in green and 0 shows "Offline" in red.

Connection Usage

mysql_global_status_threads_connected
  / mysql_global_variables_max_connections * 100

A gauge with thresholds at 70 and 85 warns before the server refuses new clients.

Queries per Second

rate(mysql_global_status_queries[$__rate_interval])

A time series panel shows the workload rhythm across the day.

Slow Queries per Minute

rate(mysql_global_status_slow_queries[$__rate_interval]) * 60

A rising line points to missing indexes or heavy reports.

Running Threads

mysql_global_status_threads_running

A sustained high value means queries queue up and wait.

Read a Healthy and an Unhealthy Pattern

Healthy                         Unhealthy
Connections                     Connections
 |   __    __                    |            ____
 |__/  \__/  \__                 |        ___/    (limit reached)
 +---------------                |_______/
                                 +---------------

The healthy line moves in a steady rhythm. In contrast, the unhealthy line climbs until it hits the limit, and new connections fail.

Check Buffer Pool Health

InnoDB keeps frequently used data in memory, in an area called the buffer pool. A healthy server answers most reads from memory. Servers that read from disk too often slow down.

rate(mysql_global_status_innodb_buffer_pool_reads[$__rate_interval])
  / rate(mysql_global_status_innodb_buffer_pool_read_requests[$__rate_interval])

The result shows the share of reads that missed memory. A value close to zero is excellent. Rising values suggest the buffer pool is too small for your data.

Add Network and Traffic Panels

Track bytes sent and received to see how much data your queries move.

rate(mysql_global_status_bytes_received[$__rate_interval])
rate(mysql_global_status_bytes_sent[$__rate_interval])

A sudden jump in bytes sent often points to a report that downloads a huge table. Share the time of the jump with the application team, and they find the cause quickly.

Follow a Slow Query Investigation

  1. The slow query panel climbs at 14:00.
  2. The running threads panel shows queries piling up at the same minute.
  3. A look at the slow query log reveals a report that scans a table with no index.
  4. The team adds an index, and both panels return to normal.

The dashboard tells you when and how bad. Only the slow query log names the query. Together they guide the fix.

Alert Ideas

AlertConditionPending Period
Database downmysql_up equals 01 minute
Connections highUsage above 85 percent5 minutes
Slow queries risingMore than 10 per minute10 minutes

Security Notes

  • Allow port 9104 only from the Prometheus server.
  • Give the monitoring user the smallest set of rights.
  • Protect the credentials file with strict permissions.
  • Use TLS between components in production networks.