CubeAPM
CubeAPM CubeAPM

How to Monitor MySQL Slow Queries and Performance

How to Monitor MySQL Slow Queries and Performance

Table of Contents

When your application starts lagging, the database is often the first suspect. MySQL is powerful, but poorly optimized queries can silently drain resources and frustrate users. MySQL slow query monitoring helps you find these problem queries before they become outages.

This guide walks you through every practical method: enabling and reading the slow query log, using performance_schema, running EXPLAIN, and choosing the right monitoring tool for your environment. Whether you run MySQL on bare metal, Amazon RDS, Google Cloud SQL, or in a container, the same core principles apply.

Key Takeaways

  • The MySQL slow query log is your starting point: enable it with slow_query_log=1 and set long_query_time to 1 second or less.
  • Use performance_schema to identify slow queries in real time without writing to disk.
  • The mysqldumpslow and pt-query-digest tools parse log files and group similar queries for faster analysis.
  • EXPLAIN and EXPLAIN ANALYZE show you exactly why a query is slow and whether indexes are being used.
  • Missing indexes are the most common cause of slow queries: rows_examined far exceeding rows_sent is a reliable signal.
  • Cloud databases (RDS, Cloud SQL, Azure) expose slow query controls through flags and dashboards, not config files.
  • APM tools like CubeAPM give you end-to-end visibility from application request to database query execution time.

What Counts as a Slow MySQL Query?

MySQL considers a query slow when its execution time exceeds the value set in long_query_time. The default is 10 seconds, which is far too high for most web applications. Many teams set this to 1 second or even 0.5 seconds to catch more queries early.

A query can be slow for several reasons:

  • Full table scans because no index exists or the optimizer cannot use one
  • Lock contention from concurrent writes
  • Sorting and grouping large result sets without indexes
  • N+1 query patterns from ORM frameworks
  • Insufficient memory forcing disk-based temp tables

A useful signal: compare rows_examined to rows_sent in the slow query log. If a query examines 500,000 rows but only returns 10, something is wrong. This ratio is one of the clearest indicators of a missing index or a poorly written query.

Method 1: Enable and Use the MySQL Slow Query Log

The slow query log is MySQL’s built-in mechanism for recording queries that exceed your defined time threshold. It is the most widely used and simplest way to start mysql slow query monitoring.

Enabling via the Configuration File (Persistent)

Edit your my.cnf or my.ini file and add these lines under the [mysqld] section:

[mysqld]slow_query_log            = 1slow_query_log_file       = /var/log/mysql/mysql-slow.loglong_query_time           = 1log_queries_not_using_indexes = 1min_examined_row_limit    = 100

Restart MySQL for the changes to take effect:

sudo systemctl restart mysql

Enabling at Runtime (No Restart Required)

If you cannot restart MySQL, enable the slow log live from a MySQL session:

SET GLOBAL slow_query_log          = 'ON';SET GLOBAL slow_query_log_file     = '/var/log/mysql/mysql-slow.log';SET GLOBAL long_query_time         = 1;SET GLOBAL log_queries_not_using_indexes = 'ON';

These settings take effect immediately but will be lost on server restart unless you also update my.cnf.

Key Configuration Parameters

ParameterWhat It DoesRecommended Value
slow_query_logEnables or disables slow query logging1 (ON)
long_query_timeThreshold in seconds; queries above this are logged1 (or 0.5 for high-traffic apps)
slow_query_log_filePath to the log file/var/log/mysql/mysql-slow.log
log_queries_not_using_indexesLogs all queries without an index, regardless of time1 (ON)
min_examined_row_limitSkip logging queries examining fewer than N rows100

Reading the Slow Query Log

A typical entry in the slow query log looks like this:

# Time: 2025-12-01T14:32:01.123456Z# User@Host: app_user[app_user] @ localhost []  Id: 42# Query_time: 4.832150  Lock_time: 0.000321  Rows_sent: 10  Rows_examined: 872541SET timestamp=1701441121;SELECT * FROM orders WHERE customer_id = 1234 ORDER BY created_at DESC;

Key fields to pay attention to:

  • Query_time: total execution time in seconds
  • Lock_time: time spent waiting for a lock (high values indicate write contention)
  • Rows_examined vs Rows_sent: a large gap means the query scanned many rows it did not need

Method 2: Analyze Logs with mysqldumpslow and pt-query-digest

Raw log files grow fast. On busy servers, you need tools to aggregate and rank queries by impact.

Using mysqldumpslow

mysqldumpslow is included with every MySQL installation. It groups similar queries (replacing literal values with N or S) and sorts them by execution time:

# Show the 10 slowest queriesmysqldumpslow -t 10 /var/log/mysql/mysql-slow.log
# Sort by total time, show top 5mysqldumpslow -s t -t 5 /var/log/mysql/mysql-slow.log

Using pt-query-digest (Percona Toolkit)

pt-query-digest from the Percona Toolkit is more powerful. It produces a report ranking queries by total execution time, count, and average time:

# Install Percona Toolkit (Ubuntu/Debian)sudo apt-get install percona-toolkit
# Analyze the slow query logpt-query-digest /var/log/mysql/mysql-slow.log

The output shows each query fingerprint ranked by total time consumed. Focus on the top 3-5 queries by total time: fixing them usually delivers the biggest performance gains.

Method 3: Use performance_schema for Real-Time Monitoring

performance_schema is an in-memory storage engine that captures detailed runtime statistics about MySQL execution. Unlike the slow query log (which writes to disk), performance_schema works in memory and is available by default in MySQL 5.6 and later.

Check that it is enabled:

SHOW VARIABLES LIKE 'performance_schema';-- Expected output:-- +--------------------+-------+-- | Variable_name      | Value |-- +--------------------+-------+-- | performance_schema | ON    |-- +--------------------+-------+

Finding the Slowest Queries

Query the events_statements_summary_by_digest table to find queries by total execution time:

SELECT  DIGEST_TEXT,  COUNT_STAR                       AS exec_count,  ROUND(SUM_TIMER_WAIT / 1e12, 2)  AS total_time_sec,  ROUND(AVG_TIMER_WAIT / 1e12, 4)  AS avg_time_sec,  SUM_ROWS_EXAMINED,  SUM_ROWS_SENTFROM performance_schema.events_statements_summary_by_digestORDER BY total_time_sec DESCLIMIT 10;

Finding Queries Not Using Indexes

SELECT  DIGEST_TEXT,  COUNT_STAR,  SUM_NO_INDEX_USED,  SUM_NO_GOOD_INDEX_USEDFROM performance_schema.events_statements_summary_by_digestWHERE SUM_NO_INDEX_USED > 0ORDER BY SUM_NO_INDEX_USED DESCLIMIT 10;

Any query showing a high SUM_NO_INDEX_USED count should be reviewed with EXPLAIN immediately.

Method 4: Use EXPLAIN to Understand Why a Query Is Slow

Once you have identified a problem query, EXPLAIN tells you how MySQL plans to execute it. This is the most important step in diagnosing and fixing a slow query.

EXPLAIN SELECT * FROM orders WHERE customer_id = 1234 ORDER BY created_at DESC;

Key EXPLAIN Output Columns

ColumnWhat to Look For
typeALL means a full table scan and is a problem. ref, eq_ref, const are efficient.
keyNULL means no index was used. If key is NULL and type is ALL, add an index.
rowsEstimated number of rows MySQL will examine. Lower is better.
ExtraUsing filesort or Using temporary indicate costly operations.

Using EXPLAIN ANALYZE (MySQL 8.0+)

EXPLAIN ANALYZE actually runs the query and shows real execution times for each step:

EXPLAIN ANALYZESELECT * FROM orders WHERE customer_id = 1234 ORDER BY created_at DESC;

This is the most accurate way to measure query performance because it shows actual row counts and time spent at each stage of execution.

Method 5: Monitor MySQL Performance Metrics in Real Time

The slow query log captures problems after they happen. To monitor MySQL health proactively, you should also track key server-level metrics.

Key Metrics to Monitor

MetricHow to CheckWhat It Means
Slow_queriesSHOW GLOBAL STATUS LIKE ‘Slow_queries’Total slow queries since last restart. Compare the rate over time.
QuestionsSHOW GLOBAL STATUS LIKE ‘Questions’Total queries executed. Use with Slow_queries for a slow query rate.
Threads_connectedSHOW GLOBAL STATUS LIKE ‘Threads_connected’Active connections. Near max_connections means connection saturation.
Innodb_row_lock_waitsSHOW GLOBAL STATUS LIKE ‘Innodb_row_lock_waits’InnoDB row lock contention. High values suggest write conflicts.
Handler_read_rnd_nextSHOW GLOBAL STATUS LIKE ‘Handler_read_rnd_next’Full table scan activity. High values point to missing indexes.

Checking the Current Slow Query Rate

-- Total slow queriesSHOW GLOBAL STATUS LIKE 'Slow_queries';
-- Current long_query_time settingSHOW VARIABLES LIKE 'long_query_time';

MySQL Slow Query Monitoring on Cloud Databases

Cloud-managed MySQL instances handle the underlying server but you still need to configure slow query logging through their respective interfaces.

Amazon RDS for MySQL

On Amazon RDS, you cannot edit my.cnf directly. Instead, use a custom DB parameter group:

  • Set slow_query_log = 1 in your RDS parameter group
  • Set long_query_time to your threshold (start with 1)
  • Set log_output = FILE to integrate with Amazon CloudWatch Logs
  • Use the RDS Database Insights dashboard to view slow SQL queries in a visual timeline

Google Cloud SQL for MySQL

On Cloud SQL, configure slow query logging using gcloud CLI flags or the Cloud Console:

gcloud sql instances patch my-mysql-instance  --database-flags  slow_query_log=on, long_query_time=1, log_output=FILE

Logs integrate with Cloud Logging (formerly Stackdriver), giving you search, filtering, and alerting. You can set a fractional threshold (e.g., 0.5) to capture sub-second queries. 

Azure Database for MySQL

Azure exposes the slow query log as the Query Performance Insight blade in the Azure portal. You can configure slow_query_log and long_query_time through Server Parameters in the portal without touching a config file. 

Fixing Slow Queries: Common Solutions

Finding slow queries is only half the work. Here are the most effective fixes, in order of impact:

1. Add Missing Indexes

If EXPLAIN shows type: ALL or key: NULL, the query is doing a full table scan. Add an index on the columns in your WHERE, ORDER BY, and JOIN clauses:

-- Check existing indexesSHOW INDEX FROM orders;
-- Add a composite indexALTER TABLE orders ADD INDEX idx_customer_created (customer_id, created_at);

2. Rewrite the Query

Avoid SELECT * and retrieve only the columns you need. Replace correlated subqueries with JOINs. Break complex queries into smaller, indexed lookups.

3. Optimize Schema Design

Use appropriate data types (INT instead of VARCHAR for numeric IDs). Normalize data to reduce duplication. Add covering indexes for your most frequent query patterns.

4. Check InnoDB Buffer Pool

If your working dataset fits in memory, MySQL can serve most queries from the buffer pool without disk I/O. A common guideline is to set innodb_buffer_pool_size to 70-80% of available RAM on a dedicated database server:

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- Check buffer pool hit rate (should be above 99%)SHOW STATUS LIKE 'Innodb_buffer_pool_read%';

Monitor MySQL Slow Queries with CubeAPM

CubeAPM gives you out-of-the-box visibility into your MySQL slow queries alongside application traces, so you can see exactly which API endpoint triggered a slow query and why.

No manual log parsing. No config files. Connect your MySQL instance and get slow query insights, query fingerprinting, latency trends, and alerts in minutes.

Try CubeAPM for MySQL Monitoring

Conclusion

Disclaimer: This article is for informational purposes only. MySQL configurations and cloud platform interfaces may change over time, so always refer to official documentation before making changes to a production environment.

Further Reading

If you found this guide helpful, these articles cover related ground:

  • How to Monitor AWS RDS Postgres Slow Queries
  • Best RDS Monitoring Tools
  • AWS RDS CloudWatch Metrics You Should Be Tracking

FAQs

1. What is a good value for long_query_time?

Start with 1 second. For high-traffic applications where user experience is sensitive to latency, reduce it to 0.5 or even 0.1 seconds. After a few days, review the log and address the most frequent or most time-consuming queries before lowering the threshold further.

2. Does enabling the slow query log impact MySQL performance?

Minimal impact at long_query_time = 1 or higher. On very busy servers logging sub-second queries, disk I/O from writing the log file can add a small overhead. Using log_output = TABLE (writing to the slow_log table in memory) or setting min_examined_row_limit = 100 reduces this.

3. How do I find slow queries without the slow query log?

Query performance_schema.events_statements_summary_by_digest for cumulative statistics. This approach captures all queries in memory without disk writes and is ideal for high-throughput servers where you cannot afford the I/O of file-based logging.

4. What is the difference between query time and lock time in the slow query log?

Query_time is the total wall-clock time for the query. Lock_time is the portion spent waiting for a table or row lock. If Lock_time is a large fraction of Query_time, the bottleneck is write contention rather than query structure, and indexing alone will not fix it.

5. Can I monitor MySQL slow queries in a containerized environment?

Yes. For MySQL running in Docker or Kubernetes, map a volume for the slow query log file so it persists outside the container. Alternatively, set log_output = TABLE, then connect to the container and query the mysql.slow_log table directly.

×
×