Monitoring Percona Server: MySQL, MongoDB, PMM Integration, and Vigilmon for Database SLAs
Percona Server for MySQL and Percona Server for MongoDB are production-hardened forks of their upstream counterparts, adding observability hooks, improved diagnostics, and performance instrumentation. This guide covers what to monitor in a Percona deployment, how to use Percona Monitoring and Management (PMM), and how to wire up Vigilmon for external database SLA enforcement.
Monitoring Percona Server for MySQL
Slow Query Detection
The most actionable signal in any MySQL deployment is the slow query log. Percona Server extends it with microsecond timestamps and extra fields:
-- Enable slow query log
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- log queries > 1 second
SET GLOBAL log_slow_extra = 'ON'; -- Percona-specific: extra fields
-- Find the log location
SHOW VARIABLES LIKE 'slow_query_log_file';
Parse the slow query log with pt-query-digest from Percona Toolkit:
pt-query-digest /var/log/mysql/slow.log \
--limit 10 \
--output json > slow_query_report.json
For real-time visibility, set log_output = TABLE and query mysql.slow_log:
SELECT
sql_text,
query_time,
lock_time,
rows_examined,
rows_sent,
start_time
FROM mysql.slow_log
ORDER BY query_time DESC
LIMIT 20;
InnoDB Buffer Pool Health
The InnoDB buffer pool is your primary performance lever. Monitor hit ratio and dirty page ratio:
SELECT
(1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)) * 100
AS buffer_pool_hit_ratio_pct,
(Innodb_buffer_pool_pages_dirty / Innodb_buffer_pool_pages_total) * 100
AS dirty_pages_pct,
Innodb_buffer_pool_pages_free,
Innodb_buffer_pool_pages_total
FROM (
SELECT
VARIABLE_VALUE AS Innodb_buffer_pool_reads
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads'
) r
CROSS JOIN (
SELECT VARIABLE_VALUE AS Innodb_buffer_pool_read_requests
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'
) rr
-- ... (simplify by querying global_status directly)
;
-- Simpler version
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool%';
Target metrics:
- Hit ratio > 99% (below 95% means the buffer pool is undersized)
- Dirty pages < 75% (high dirty ratio causes checkpoint stalls)
Replication Lag
For MySQL replication, the standard check:
SHOW SLAVE STATUS\G
-- or on MySQL 8+
SHOW REPLICA STATUS\G
Key fields:
Seconds_Behind_Master— lag in seconds; alert > 30sSlave_IO_Running: Yes— IO thread must be runningSlave_SQL_Running: Yes— SQL thread must be runningLast_Error— non-empty means replication has broken
Automate this check:
mysql -u monitor -ppassword -e "SHOW SLAVE STATUS\G" \
| grep -E 'Seconds_Behind_Master|Slave_IO_Running|Slave_SQL_Running|Last_Error'
Connection and Thread Health
-- Current connections by state
SELECT STATE, COUNT(*) AS cnt
FROM information_schema.PROCESSLIST
GROUP BY STATE
ORDER BY cnt DESC;
-- Max connections utilization
SELECT
VARIABLE_VALUE AS max_connections
FROM performance_schema.global_variables
WHERE VARIABLE_NAME = 'max_connections';
SELECT
VARIABLE_VALUE AS threads_connected
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Threads_connected';
Alert when Threads_connected / max_connections > 0.8.
Monitoring Percona Server for MongoDB
Replication Lag
In a MongoDB replica set, replication lag is the delta between the primary's oplog and a secondary's last applied optime:
// In mongosh
rs.printSecondaryReplicationInfo()
// Programmatic
const status = rs.status();
status.members.forEach(m => {
if (m.state === 2) { // SECONDARY
const lagSeconds = (status.members[0].optimeDate - m.optimeDate) / 1000;
print(`${m.name}: lag=${lagSeconds}s`);
}
});
Alert when lag exceeds your maxStalenessSeconds read preference setting.
WiredTiger Cache Health
db.serverStatus().wiredTiger.cache
// Key fields:
// "bytes currently in the cache"
// "maximum bytes configured"
// "pages read into cache"
// "pages written from cache"
// "tracked dirty bytes in the cache"
# Via mongostat
mongostat --host localhost:27017 \
-u admin -p password \
--authenticationDatabase admin \
-n 60 \
--humanReadable
Watch faults (page faults indicate cache pressure) and qrw (queued reads/writes indicate lock contention).
Oplog Window
The oplog window determines how long a secondary can be offline before it needs a full resync:
// Check oplog window size in hours
const oplog = db.getSiblingDB('local').oplog.rs;
const firstTs = oplog.find().sort({$natural: 1}).limit(1).next().ts;
const lastTs = oplog.find().sort({$natural: -1}).limit(1).next().ts;
const windowHours = (lastTs.t - firstTs.t) / 3600;
print(`Oplog window: ${windowHours.toFixed(1)} hours`);
Alert when the oplog window drops below 24 hours.
PMM Integration
Percona Monitoring and Management (PMM) is the recommended observability stack for Percona deployments. It ships Grafana dashboards, Prometheus exporters, and query analytics out of the box.
Install PMM Server
docker run -d \
-p 80:80 -p 443:443 \
--name pmm-server \
percona/pmm-server:2
Register a MySQL Client
# Install pmm-client on the database host
apt-get install pmm2-client
# Configure server connection
pmm-admin config \
--server-insecure-tls \
--server-url=https://admin:admin@pmm-server-host
# Add MySQL service
pmm-admin add mysql \
--username=pmm \
--password=pmm_password \
--host=localhost \
--port=3306 \
--service-name=prod-mysql
Register a MongoDB Client
pmm-admin add mongodb \
--username=pmm \
--password=pmm_password \
--host=localhost \
--port=27017 \
--service-name=prod-mongodb
PMM will now scrape metrics every 5 seconds and populate the built-in dashboards for query analytics, InnoDB metrics, replication lag, and more.
Vigilmon Integration
PMM is excellent for internal observability, but Vigilmon provides an external SLA enforcement layer — confirming your databases are reachable from outside your network and alerting your on-call team via independent channels.
Step 1 — create a health check endpoint
from flask import Flask, jsonify
import pymysql
import pymongo
app = Flask(__name__)
MYSQL_CONFIG = {
"host": "localhost", "port": 3306,
"user": "monitor", "password": "monitor_pass",
"database": "mysql", "connect_timeout": 3
}
MONGO_URI = "mongodb://monitor:monitor_pass@localhost:27017/admin"
@app.route("/health/percona/mysql")
def mysql_health():
try:
conn = pymysql.connect(**MYSQL_CONFIG)
cur = conn.cursor()
# Check replication
cur.execute("SHOW SLAVE STATUS")
row = cur.fetchone()
if row:
lag = row[32] # Seconds_Behind_Master
io_running = row[10] # Slave_IO_Running
sql_running = row[11] # Slave_SQL_Running
if io_running != "Yes" or sql_running != "Yes":
conn.close()
return jsonify({"error": "replication stopped"}), 503
if lag is not None and lag > 30:
conn.close()
return jsonify({"error": f"replication lag {lag}s"}), 503
conn.close()
return jsonify({"status": "ok"}), 200
except Exception as e:
return jsonify({"error": str(e)}), 503
@app.route("/health/percona/mongodb")
def mongo_health():
try:
client = pymongo.MongoClient(MONGO_URI, serverSelectionTimeoutMS=3000)
client.admin.command("ping")
# Check replica set health
status = client.admin.command("replSetGetStatus")
primary_count = sum(1 for m in status["members"] if m["stateStr"] == "PRIMARY")
if primary_count == 0:
return jsonify({"error": "no primary in replica set"}), 503
return jsonify({"status": "ok", "primary_count": primary_count}), 200
except Exception as e:
return jsonify({"error": str(e)}), 503
if __name__ == "__main__":
app.run(host="0.0.0.0", port=9090)
Step 2 — add Vigilmon monitors
In Vigilmon, configure:
- HTTP monitor →
https://your-host:9090/health/percona/mysql— interval 60s - HTTP monitor →
https://your-host:9090/health/percona/mongodb— interval 60s - TCP monitor →
mysql-host:3306— basic connectivity - TCP monitor →
mongo-host:27017— basic connectivity
Set up alert policies pointing to PagerDuty, Slack, or email for each monitor.
Alert Thresholds
| Metric | Warning | Critical | |--------|---------|----------| | MySQL slow query rate | > 5/min | > 50/min | | InnoDB hit ratio | < 98% | < 95% | | Replication lag (MySQL) | > 10s | > 60s | | Threads_connected / max | > 70% | > 90% | | MongoDB replication lag | > 30s | > 120s | | WiredTiger cache dirty % | > 20% | > 40% | | Oplog window | < 48h | < 12h |
Conclusion
Percona Server provides richer diagnostics than upstream MySQL and MongoDB, and PMM gives you a purpose-built monitoring stack for Percona deployments. Pair PMM's internal dashboards with Vigilmon's external HTTP and TCP monitors to cover both in-cluster observability and external SLA verification. With slow query alerts, replication lag checks, and buffer pool monitoring in place, your Percona databases can run in production with confidence.