MySQL alert rules for Prometheus: 11 rules with runbooks
11 ready-to-use MySQL alert rules in PromQL, each with severity, duration and runbook steps. Metrics from mysqld_exporter, Categraf. Download as a Prometheus rules file or import into Nightingale.
Last reviewed
MySQL alert rules for the failures that page people in practice: an instance that is down or has just restarted, slow queries piling up, connections approaching max_connections, too many running threads, InnoDB log waits, open files nearing the limit, and replication problems (IO or SQL thread stopped, replica lag). The exporter group uses mysqld_exporter metric names (mysql_global_status_*, mysql_slave_status_*); each rule comes with the first commands to run, such as SHOW FULL PROCESSLIST and pt-query-digest, when it fires.
At a glance
- 11 rules, each with a PromQL condition, a severity, a
forduration and runbook steps - Metrics from: mysqld_exporter, Categraf
- Download:
mysql.yml, a standard Prometheus rules file (groups:format), checked withpromtool check rules - Thresholds are starting points. Adjust them to your environment before enabling the rules.
Rule list
| Rule | Severity | For |
|---|---|---|
| More than 60% of the connections in MySQL are in a running state | Warning | 2m |
| More than 80% of MySQL files open | Warning | 2m |
| MySQL connection count has exceeded 80% | Warning | 2m |
| Mysql has just restarted. Please be advised - exporter | Info | — |
| MySQL slow queries are piling up | Warning | 2m |
| MysqlInnodbLogWaits - exporter | Warning | — |
| MysqlSlaveIoThreadNotRunning - exporter | Critical | — |
| MysqlSlaveReplicationLag - exporter | Critical | 1m |
| MysqlSlaveSqlThreadNotRunning - exporter | Critical | — |
| The MySQL instance is down | Critical | — |
| Mysql has opened a large number of file handles. Please be aware - categraf | Warning | 2m |
Prometheus exporter (10)
9 of the 10 rules in this group also apply unchanged to instances collected by Categraf, which produces the same metric names.
More than 60% of the connections in MySQL are in a running state
Warning · 2m · Trigger:
avg by (instance) (mysql_global_status_threads_running) / avg by (instance) (mysql_global_variables_max_connections) * 100 > 60
Runbook:
- Run SHOW FULL PROCESSLIST to see which SQL statement and which table the piled-up threads are concentrated on;
- Run SHOW ENGINE INNODB STATUS to check for lock waits or deadlocks;
- KILL the offending SQL to stop the bleeding, then add indexes or apply rate limiting;
- Check whether an upstream traffic spike or a slow dependency is keeping connections from being released.
More than 80% of MySQL files open
More than 80% of MySQL files open
Warning · 2m · Trigger:
avg by (instance) (mysql_global_status_innodb_num_open_files) / avg by (instance)(mysql_global_variables_open_files_limit) * 100 > 80
Runbook:
- Run SHOW GLOBAL STATUS LIKE 'Open_files' and SHOW VARIABLES LIKE 'open_files_limit' to confirm the current level;
- Raise open_files_limit in my.cnf and raise the system ulimit -n and the systemd LimitNOFILE to match;
- Check whether table_open_cache is set too large and inflating the handle count;
- Check whether a large number of partitioned or small tables are being accessed at once.
MySQL connection count has exceeded 80%
More than 80% of MySQL connections are in use
Warning · 2m · Trigger:
avg by (instance) (mysql_global_status_threads_connected) / avg by (instance) (mysql_global_variables_max_connections) * 100 > 80
Runbook:
- Run SHOW FULL PROCESSLIST and group connections by source host to find the application with an abnormal connection count;
- Tell a traffic spike apart from an application connection pool leak (many long-lived Sleep connections piling up);
- As an emergency measure raise max_connections, checking free memory at the same time to avoid an OOM;
- For the root cause, cap the application connection pool and shorten wait_timeout.
Mysql has just restarted. Please be advised - exporter
MySQL has just been restarted, less than one minute ago
Info · — · Trigger:
mysql_global_status_uptime < 60
Runbook:
- Check the error log (the file pointed to by SHOW VARIABLES LIKE 'log_error') to tell a crash, an OOM kill and a manual restart apart;
- If it was an OOM, compare innodb_buffer_pool_size against the machine's physical memory and lower it;
- If the restart was unplanned, check whether systemd or the container orchestrator is repeatedly restarting it;
- After the restart, confirm replication resumed automatically and application connection pools reconnected.
MySQL slow queries are piling up
MySQL slow queries are piling up over the last 5 minutes
Warning · 2m · Trigger:
increase(mysql_global_status_slow_queries[5m]) > 10
Runbook:
- Run SHOW FULL PROCESSLIST to find long-running SQL and KILL <id> to stop the bleeding if needed;
- Use mysqldumpslow -s t -t 10 <slow_log> or pt-query-digest to find the top slow queries;
- Run EXPLAIN on the queries you found to inspect the plan, then add indexes or rewrite them;
- If the noise comes from long_query_time being set too low, tune that parameter instead of ignoring the alert.
MysqlInnodbLogWaits - exporter
MySQL innodb log writes stalling
Warning · — · Trigger:
rate(mysql_global_status_innodb_log_waits[15m]) > 10
Runbook:
- Raise innodb_log_buffer_size (typically doubling the 16M default up to 64M~256M);
- Check whether innodb_log_file_size is too small and causing frequent checkpoints;
- Run iostat -x 1 to see whether the disk holding the redo log is already at full utilization;
- Check for large transactions writing too much data at once and split them into smaller batches.
MysqlSlaveIoThreadNotRunning - exporter
MySQL Slave IO thread not running
Critical · — · Trigger:
mysql_slave_status_master_server_id > 0 and ON (instance) mysql_slave_status_slave_io_running == 0
Runbook:
- Run SHOW SLAVE STATUS\G on the replica and read Last_IO_Error;
- The usual causes are the primary being unreachable, an invalid replication account, or the required binlog having been purged — fix the network, reset the account with CHANGE MASTER TO, or rebuild the replica from a backup respectively;
- Then run START SLAVE IO_THREAD and confirm Slave_IO_Running=Yes;
- Take read traffic off this replica before you start.
MysqlSlaveReplicationLag - exporter
Critical · 1m · Trigger:
mysql_slave_status_master_server_id > 0 and ON (instance) (mysql_slave_status_seconds_behind_master - mysql_slave_status_sql_delay) > 30
Runbook:
- Run SHOW SLAVE STATUS\G and read Seconds_Behind_Master together with the event the SQL thread is currently applying;
- On the primary, run SHOW PROCESSLIST to check for a large transaction or a bulk DML loading data;
- If the replica applies single-threaded, enable parallel replication (slave_parallel_workers / slave_parallel_type=LOGICAL_CLOCK);
- If the lag keeps growing, move read traffic back to the primary or to another replica.
MysqlSlaveSqlThreadNotRunning - exporter
MySQL Slave SQL thread not running
Critical · — · Trigger:
mysql_slave_status_master_server_id > 0 and ON (instance) mysql_slave_status_slave_sql_running == 0
Runbook:
- Run SHOW SLAVE STATUS\G on the replica and read Last_SQL_Error to identify the event it is stuck on;
- If it is a conflict that can be safely skipped (such as a duplicate primary key), verify the data is consistent, then run SET GLOBAL sql_slave_skip_counter=1 followed by START SLAVE SQL_THREAD;
- If the primary and replica data have already diverged, rebuild the replica from a backup instead of blindly skipping;
- Take read traffic off this replica before you start.
The MySQL instance is down
Critical · — · Trigger:
mysql_up == 0
Runbook:
- Log in to the host and run systemctl status mysqld or docker ps to confirm the process is alive;
- If it is alive, connect by hand with mysql -h<host> -P<port> -u<user> -p to tell a hung instance apart from a network or account problem;
- If it is not running, read the tail of the error log to identify the cause (OOM, full disk, corrupted data files) before starting it — do not blindly restart;
- If replication is in use, immediately assess whether to fail over, and confirm the application has taken this node out of rotation.
Categraf (1)
For hosts and instances collected by Categraf; metric names follow Categraf plugins.
Mysql has opened a large number of file handles. Please be aware - categraf
More than 80% of MySQL files open
Warning · 2m · Trigger:
avg by (instance) (mysql_global_status_open_files) / avg by (instance)(mysql_global_variables_open_files_limit) * 100 > 80
Runbook:
- Run SHOW GLOBAL STATUS LIKE 'Open_files' and SHOW VARIABLES LIKE 'open_files_limit' to confirm the current level;
- Raise open_files_limit in my.cnf and raise the system ulimit -n and the systemd LimitNOFILE to match;
- Check whether table_open_cache is set too large and inflating the handle count;
- Check whether a large number of partitioned or small tables are being accessed at once.
How to use these rules
- With Prometheus or vmalert: download
mysql.yml, add it torule_files(or-rulefor vmalert), check the metric names against your exporter version, and tune thresholds. Severity is set as aseveritylabel (critical / warning / info), andrunbook_urlpoints back to this page, or to the rule's own page where it has one. - With Nightingale: the same rules ship in the MySQL integration template. Open the integration center, import the rules into a business group, and enable them one by one. Nightingale keeps the runbook with each alert and can evaluate the rules against Prometheus, VictoriaMetrics and other data sources.
Sources and license
The runbook steps and the remaining rules come from Nightingale's integration templates (MySQL, Apache-2.0). Corrections are welcome as pull requests there.
Related
- Monitor MySQL with Nightingale: collector config, dashboards and metric reference
- Write a metric rule in Nightingale
- All alert rules