DEV Community

Vigilmon
Vigilmon

Posted on

How to Monitor MySQL Database Health with Vigilmon (Free External Uptime Checks)

MySQL powers millions of applications. When it goes down or becomes unreachable, your entire app follows. This guide shows how to monitor MySQL health externally using Vigilmon - no agent installation, no database credentials exposed to your monitoring tool.

Why External MySQL Monitoring Matters

Database-internal tools (MySQL slow query log, Performance Schema, SHOW PROCESSLIST) tell you what's happening inside MySQL. But they don't catch:

  • Connection refused: MySQL is listening but your app can't reach it (firewall rule change, bind-address misconfiguration)
  • Connection pool exhausted: Too many connections, app starts failing even though MySQL is "up"
  • Application layer failures: MySQL is up but your ORM connection pool is broken
  • Network path failures: The database is reachable from localhost but not from your application servers

External HTTP monitoring via a health endpoint catches all of these.

Setting Up a MySQL Health Endpoint

Expose a /health/db endpoint in your application that tests the MySQL connection:

Node.js (mysql2)

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  waitForConnections: true,
  connectionLimit: 10
});

app.get('/health/db', async (req, res) => {
  try {
    const [rows] = await pool.execute('SELECT 1 AS health');
    res.json({ 
      status: 'ok', 
      db: 'connected',
      result: rows[0].health 
    });
  } catch (err) {
    res.status(503).json({ 
      status: 'error', 
      db: 'disconnected',
      message: err.message 
    });
  }
});
Enter fullscreen mode Exit fullscreen mode

PHP/Laravel

Route::get('/health/db', function () {
    try {
        $result = DB::select('SELECT 1 as health');
        return response()->json([
            'status' => 'ok',
            'db' => 'connected',
            'result' => $result[0]->health
        ]);
    } catch (\Exception $e) {
        return response()->json([
            'status' => 'error',
            'db' => 'disconnected',
            'message' => $e->getMessage()
        ], 503);
    }
});
Enter fullscreen mode Exit fullscreen mode

Python/Django

from django.db import connection
from django.http import JsonResponse

def db_health(request):
    try:
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1")
            cursor.fetchone()
        return JsonResponse({"status": "ok", "db": "connected"})
    except Exception as e:
        return JsonResponse(
            {"status": "error", "db": str(e)}, 
            status=503
        )
Enter fullscreen mode Exit fullscreen mode

Ruby on Rails

get '/health/db', to: proc { |env|
  begin
    ActiveRecord::Base.connection.execute("SELECT 1")
    [200, {"Content-Type" => "application/json"}, ['{"status":"ok","db":"connected"}']]
  rescue => e
    [503, {"Content-Type" => "application/json"}, ["{\"status\":\"error\",\"db\":\"#{e.message.to_json}\"}"]]
  end
}
Enter fullscreen mode Exit fullscreen mode

Go

func dbHealthHandler(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
        defer cancel()

        if err := db.PingContext(ctx); err != nil {
            w.WriteHeader(http.StatusServiceUnavailable)
            json.NewEncoder(w).Encode(map[string]string{
                "status": "error", 
                "db": err.Error(),
            })
            return
        }
        json.NewEncoder(w).Encode(map[string]string{
            "status": "ok", 
            "db": "connected",
        })
    }
}
Enter fullscreen mode Exit fullscreen mode

Configuring Vigilmon for MySQL Health Monitoring

Once your health endpoint is live:

  1. Sign up at vigilmon.online
  2. Add a new HTTP(S) monitor:
URL: https://yourapp.com/health/db
Method: GET
Expected status: 200
Keyword check: "connected"
Interval: 3 minutes
Multi-region: enabled
Enter fullscreen mode Exit fullscreen mode

The keyword check confirms MySQL is actually connected, not just that the endpoint returned 200. If your app incorrectly returns 200 when the DB is down, the keyword check catches it.

Monitoring MySQL Replication

If you use MySQL replication (master-replica), monitor the replica health separately:

Monitor 1: Primary    yourapp.com/health/db
Monitor 2: Replica    yourapp.com/health/db-replica
Enter fullscreen mode Exit fullscreen mode

Your replica health endpoint should check both connectivity and replication lag:

app.get('/health/db-replica', async (req, res) => {
  try {
    const [rows] = await replicaPool.execute(
      'SHOW SLAVE STATUS'
    );

    const status = rows[0];
    const lag = parseInt(status.Seconds_Behind_Master || 0);

    if (!status.Slave_IO_Running || !status.Slave_SQL_Running) {
      return res.status(503).json({ 
        status: 'error', 
        replication: 'stopped' 
      });
    }

    if (lag > 30) {
      return res.status(503).json({ 
        status: 'degraded', 
        lag_seconds: lag 
      });
    }

    res.json({ 
      status: 'ok', 
      replication: 'running',
      lag_seconds: lag 
    });
  } catch (err) {
    res.status(503).json({ status: 'error', db: err.message });
  }
});
Enter fullscreen mode Exit fullscreen mode

MySQL Connection Pool Monitoring

If you use connection pooling (ProxySQL, MySQL Router, or app-level pools), monitor pool saturation:

app.get('/health/pool', (req, res) => {
  const stats = {
    total: pool.pool._allConnections.length,
    free: pool.pool._freeConnections.length,
    queue: pool.pool._connectionQueue.length
  };

  if (stats.queue > 5) {
    return res.status(503).json({ 
      status: 'degraded', 
      pool: stats,
      message: 'Connection queue building up'
    });
  }

  res.json({ status: 'ok', pool: stats });
});
Enter fullscreen mode Exit fullscreen mode

What This Setup Monitors vs. What It Doesn't

Monitors:

  • Database reachability from your application
  • Connection pool health and saturation
  • Replication status and lag
  • Application-layer DB failures

Doesn't monitor (needs internal tooling):

  • Slow query performance (use slow query log)
  • Index usage and query plans (use EXPLAIN)
  • InnoDB buffer pool hit rate (use Performance Schema)
  • Disk usage and table sizes

Combine Vigilmon (external availability) with your existing MySQL monitoring tools (internal performance) for complete coverage.

Sample MySQL Monitoring Setup

Monitor 1: App + MySQL health    yourapp.com/health/db         3 min interval
Monitor 2: Replica health        yourapp.com/health/db-replica  5 min interval  
Monitor 3: Connection pool       yourapp.com/health/pool        3 min interval
Monitor 4: phpMyAdmin/adminer    dbadmin.yourapp.com            10 min interval
Enter fullscreen mode Exit fullscreen mode

Start Monitoring Your MySQL Database

Set up free database health monitoring at vigilmon.online. No agent installation, no database credentials in your monitoring tool - just an HTTP endpoint that tests connectivity from your application layer.

When MySQL goes down, you want to know before your users see a 500 error.

Top comments (0)