
MySQL monitoring is most effective when it answers a simple question: Will this issue impact users, and what should we do next? Many monitoring setups fail because they collect lots of numbers but produce alerts that are either too noisy or too vague to act on quickly.
This guide focuses on practical, query-driven monitoring for MySQL: which metrics matter, how to fetch them with SQL, and how to turn them into low-noise alerts that improve reliability without waking you up unnecessarily.
What “good” MySQL monitoring looks like
Alert on symptoms that affect users, and measure signals that explain causes.
In practice, you want:
- Fast detection of user-impacting issues (errors, saturation, replication breakage).
- Clear triage context (which host, which schema/table, what changed, trend over time).
- Secure access (read-only queries, minimal grants, encrypted connections).
- Few alerts that are actionable (avoid paging on every minor fluctuation).
Prerequisites: enable the right data sources
Modern MySQL monitoring via SQL relies on a few built-in schemas:
- Performance Schema (
performance_schema): statement latency, waits, memory, and more. - sys schema (
sys): convenience views that summarize performance schema data. - Information Schema (
information_schema): metadata like tables, indexes, and sizes.
If you’re not using performance_schema, you can still do basic monitoring (connections, replication, uptime), but you’ll miss high-value performance visibility.
Core MySQL monitoring metrics (and why they matter)
The table below groups key signals into categories you can map to alert rules.
| Category | Metric / Signal | Why it matters | Common alert pattern |
|---|---|---|---|
| Availability | Uptime / server responding | Detects outages and restart loops | Ping fails or uptime resets unexpectedly |
| Saturation | Connection usage, running threads | Overload often precedes errors/timeouts | High for N minutes + rising error rate |
| Performance | Slow statements, lock waits | Directly correlates to user latency | P95/p99 latency above baseline |
| Reliability | Replication lag / broken replication | Stale reads, failover risk | Lag above threshold or SQL thread stopped |
| Storage | Table/index growth, disk risk | Running out of space can be catastrophic | Growth rate anomaly + low free space |
| Data quality | Backlogs, stuck jobs, missing rows | Business-impacting issues without downtime | Row counts/age thresholds per workflow |
Practical SQL queries for MySQL monitoring
Below are examples you can run periodically and turn into alert conditions. Where possible, design alerts to include context (host, schema, table, counts, max age) so the notification is immediately actionable.
1) Basic availability and restart detection
-- Is MySQL responding? (any simple query works)
SELECT 1;
-- Uptime and version (detect unexpected restarts)
SHOW GLOBAL STATUS LIKE 'Uptime';
SELECT @@version AS version, @@hostname AS hostname;
Alert idea: if uptime drops (or is unexpectedly low) outside maintenance windows, notify. A “restart detected” alert is often more actionable than a generic “CPU spike” because it changes the debugging path immediately.
2) Connections and thread pressure
-- Current connections and running threads
SHOW GLOBAL STATUS WHERE Variable_name IN (
'Threads_connected',
'Threads_running',
'Max_used_connections',
'Aborted_connects'
);
-- Configured connection limit
SHOW VARIABLES LIKE 'max_connections';
Low-noise pattern: alert when Threads_running is high and rising for several intervals, or when connections are near the limit and aborted connects increase. Single-sample spikes often resolve without intervention.
3) Error-rate signals (application impact)
-- Useful counters to track over time (alert on rate of change)
SHOW GLOBAL STATUS WHERE Variable_name IN (
'Questions',
'Queries',
'Connections',
'Aborted_clients',
'Aborted_connects',
'Threads_created'
);
These are cumulative counters. The alert should be based on delta per minute (a rate), not the absolute value.
4) Replication health (classic and MySQL 8+)
If you use replication, this is among the highest ROI areas of mysql monitoring.
-- Traditional replication status (works in many setups)
SHOW SLAVE STATUS\G
-- MySQL 8+ terminology often uses REPLICA
SHOW REPLICA STATUS\G
Key fields to alert on:
- IO/SQL thread running (stopped = urgent)
- Seconds_Behind_Master (lag; use thresholds by workload)
- Last_SQL_Error (actionable error message)
Low-noise pattern: use two thresholds for lag (warning and critical), and suppress if lag is expected during known heavy batch windows.
5) Top slow queries (digest-based, via sys/performance_schema)
When performance_schema and sys are available, you can monitor statement latency without parsing logs.
-- Top statements by total latency (sys schema)
SELECT
digest_text,
count_star AS exec_count,
ROUND(sum_timer_wait/1e12, 2) AS total_seconds,
ROUND(avg_timer_wait/1e9, 2) AS avg_ms
FROM sys.statement_analysis
ORDER BY sum_timer_wait DESC
LIMIT 10;
Alert idea: notify when a new digest appears in the top N with high average latency, or when a known digest’s latency increases beyond a baseline (e.g., +50% over last hour).
6) Lock waits and contention
-- High-level lock wait summary
SELECT *
FROM sys.schema_table_lock_waits
ORDER BY wait_time DESC
LIMIT 10;
When to alert: sustained lock waits that coincide with user latency or rising Threads_running. A single lock wait can be normal; a pattern is a problem.
7) Table and index growth (capacity planning)
-- Largest tables by total size
SELECT
table_schema,
table_name,
ROUND((data_length + index_length)/1024/1024, 1) AS total_mb,
ROUND(data_length/1024/1024, 1) AS data_mb,
ROUND(index_length/1024/1024, 1) AS index_mb
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
ORDER BY (data_length + index_length) DESC
LIMIT 20;
Alert idea: track daily growth rate per table and flag anomalies (e.g., “orders_events grew 4× faster than usual”). This catches runaway logging, missing retention jobs, or unexpected ingest.
Designing alert rules that don’t create fatigue
Use symptom-first alerts (then drill down)
A simple hierarchy works well:
- Symptoms: latency, error rate, replication broken, connection exhaustion.
- Causes: slow digests, lock waits, buffer pressure, I/O saturation.
- Forensics: per-table growth, per-user load, per-host differences.
In other words: page on symptoms, and include links/queries to investigate causes.
Prefer multi-signal conditions
Single metrics are often noisy. Examples of better combinations:
- High connections + aborted connects rising → likely capacity issue
- Replication lag + SQL thread stopped → urgent, actionable
- Slow query latency spike + lock waits increase → contention suspected
Use time windows and “N out of M” logic
Instead of alerting instantly, require persistence (e.g., 3 out of 5 checks). This reduces false positives from brief spikes, network blips, or momentary load.
Security best practices for query-based MySQL monitoring
Query-driven monitoring is powerful, but only if you keep access tight.
Create a dedicated read-only monitoring user
-- Example: minimal privileges (adjust for your needs)
CREATE USER 'monitor'@'%' IDENTIFIED BY 'use-a-strong-password';
-- Basic status + metadata
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'monitor'@'%';
GRANT SELECT ON performance_schema.* TO 'monitor'@'%';
GRANT SELECT ON information_schema.* TO 'monitor'@'%';
GRANT SELECT ON sys.* TO 'monitor'@'%';
FLUSH PRIVILEGES;
Notes: avoid write privileges; use TLS; restrict by IP when possible; rotate credentials; and consider separate users per environment (prod vs staging) for auditability.
Example: an actionable mysql monitoring checklist
If you’re building a baseline monitoring pack, start small and expand:
- Availability: query success + uptime reset detection
- Connection pressure: threads connected/running + aborted connects
- Replication: thread running + lag thresholds + last error text
- Performance: top statement digests by latency + lock waits
- Capacity: largest tables + growth anomalies + low disk (from infra metrics)
Once that’s stable, add workload-specific checks (e.g., “payments queue backlog,” “stuck shipments,” “missing daily rollups”) using targeted queries against your application tables.
Putting it into a schedule (and shipping notifications)
Most teams run these queries on a cadence (every 1–5 minutes for operational signals; hourly/daily for growth and capacity). The key is consistency: sampling at predictable intervals makes trends and baselines meaningful. Notifications can go to email, chat, incident tools, or mobile push—just ensure every alert includes the query result and a clear next step.
If you prefer running scheduled MySQL queries and receiving smart notifications on iOS, tools like Query Alert can help centralize those checks without building custom polling scripts.