How to Monitor Your MySQL Database with Vigilmon
MySQL is the world's most widely deployed open-source relational database. It powers WordPress, Shopify, Joomla, countless SaaS backends, and millions of production systems. And because it's so foundational, MySQL downtime is catastrophic — broken queries, failed logins, and app crashes that take your entire service with them.
This guide shows you how to monitor MySQL effectively with Vigilmon — from HTTP health endpoints to connection pool saturation and replication lag.
Why MySQL Needs Dedicated Monitoring
MySQL fails in predictable patterns that generic uptime monitors miss:
-
Too many connections — MySQL's
max_connectionslimit causesERROR 1040: Too many connectionsunder load spikes - Replication lag — replica falls behind the primary; reads return stale data silently
- Slow query accumulation — slow queries pile up, blocking faster queries behind them
- InnoDB buffer pool pressure — disk I/O spikes when hot data doesn't fit in RAM
- Disk full — MySQL stops accepting writes with no warning
You need both liveness monitoring (is MySQL responding?) and health monitoring (is MySQL responding correctly?).
Step 1: Create a MySQL Health Check Endpoint
The cleanest solution: expose a lightweight HTTP endpoint in your application that runs a simple MySQL query and returns 200 OK or 503.
Node.js (Express) example:
const mysql = require('mysql2/promise');
const express = require('express');
const app = express();
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: 5
});
app.get('/health/db', async (req, res) => {
try {
const [rows] = await pool.query('SELECT 1 AS ok');
res.json({ status: 'ok', db: 'mysql', result: rows[0].ok });
} catch (err) {
res.status(503).json({ status: 'error', message: err.message });
}
});
app.listen(3000);
Python (FastAPI) example:
from fastapi import FastAPI, Response
import aiomysql
import asyncio
app = FastAPI()
async def get_db():
return await aiomysql.connect(
host='localhost', user='root',
password='secret', db='myapp'
)
@app.get("/health/db")
async def health_db():
try:
conn = await get_db()
async with conn.cursor() as cur:
await cur.execute("SELECT 1")
await conn.ensure_closed()
return {"status": "ok", "db": "mysql"}
except Exception as e:
return Response(content=str(e), status_code=503)
Step 2: Add an HTTP Monitor in Vigilmon
- Log in to vigilmon.online and click Add Monitor
- Type: HTTP(S)
- URL:
https://your-app.com/health/db - Interval: 60 seconds
- Alert condition: Status code is not 200, or response time > 2000ms
- Enable email or Slack alerts
Vigilmon checks from multiple global regions simultaneously. If your MySQL connection pool exhausts in US-East but not EU, you'll know exactly where the failure originated.
Step 3: Monitor MySQL Replication Lag
If you run MySQL replicas (read slaves), replication lag is a silent killer. Your application reads stale data without any visible error.
Add this to your health endpoint for replica instances:
@app.get("/health/replica")
async def health_replica():
try:
conn = await get_db()
async with conn.cursor() as cur:
await cur.execute("SHOW SLAVE STATUS")
result = await cur.fetchone()
if result is None:
return Response(content="Not a replica", status_code=200)
lag = result[32] # Seconds_Behind_Master
if lag is None or lag > 30:
return Response(
content=f"Replica lag: {lag}s",
status_code=503
)
return {"status": "ok", "replication_lag_seconds": lag}
except Exception as e:
return Response(content=str(e), status_code=503)
Now add a second Vigilmon monitor pointing to /health/replica with an alert threshold if it returns 503 (lag > 30 seconds).
Step 4: Connection Pool Saturation Check
MySQL's max_connections is frequently hit by apps during traffic spikes. Add a check:
SELECT
(SELECT COUNT(*) FROM information_schema.PROCESSLIST) AS current_connections,
@@max_connections AS max_connections,
ROUND(
(SELECT COUNT(*) FROM information_schema.PROCESSLIST) / @@max_connections * 100, 1
) AS pct_used;
Return 503 if connection pool utilization exceeds 80%:
app.get('/health/connections', async (req, res) => {
const [[row]] = await pool.query(`
SELECT
(SELECT COUNT(*) FROM information_schema.PROCESSLIST) AS curr,
@@max_connections AS max_conn
`);
const pct = (row.curr / row.max_conn) * 100;
if (pct > 80) {
return res.status(503).json({ status: 'saturated', pct_used: pct });
}
res.json({ status: 'ok', pct_used: pct });
});
MySQL Monitoring Coverage Table
| Monitor Type | Endpoint | Alerts On |
|---|---|---|
| HTTP(S) | /health/db |
DB unreachable or slow |
| HTTP(S) | /health/replica |
Replication lag > 30s |
| HTTP(S) | /health/connections |
Pool > 80% utilized |
| SSL Certificate | yourdomain.com |
Cert expiry < 14 days |
Common MySQL Failure Patterns Vigilmon Catches
Connection pool exhaustion: A Black Friday traffic spike exhausted max_connections=100 in 30 seconds. The health check fired before the 500 errors hit users.
Replication lag spike: A large batch DELETE on the primary caused the replica to fall 90 seconds behind. Reads served stale order data for 2 minutes — the replica monitor caught it at 31 seconds lag.
Disk full at 3 AM: MySQL stopped accepting INSERT statements when the data disk hit 100%. The DB health endpoint returned 503; Vigilmon paged the on-call within 90 seconds.
Conclusion
MySQL monitoring needs more than a simple ping. With Vigilmon's multi-region HTTP monitoring and custom health endpoints, you get real-time alerts for the failure modes that actually matter: connection exhaustion, replication lag, and disk pressure.
Start monitoring your MySQL database free at vigilmon.online
Top comments (0)