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
| Metric | Plain Meaning |
|---|---|
| mysql_up | 1 when the exporter reaches MySQL, 0 when it cannot |
| mysql_global_status_threads_connected | Open client connections |
| mysql_global_variables_max_connections | The connection limit |
| mysql_global_status_queries | Total queries, as a growing counter |
| mysql_global_status_slow_queries | Queries slower than the slow query limit |
| mysql_global_status_threads_running | Queries that execute right now |
Build the Panels
Database Status
mysql_upUse 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_runningA 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
- The slow query panel climbs at 14:00.
- The running threads panel shows queries piling up at the same minute.
- A look at the slow query log reveals a report that scans a table with no index.
- 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
| Alert | Condition | Pending Period |
|---|---|---|
| Database down | mysql_up equals 0 | 1 minute |
| Connections high | Usage above 85 percent | 5 minutes |
| Slow queries rising | More than 10 per minute | 10 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.
