MySQL slow query log, explained
The slow query log is the cheapest database profiler you already have. Each entry is one statement that ran at least long_query_time (or used no index, if log_queries_not_using_indexes is on), with how long it ran, how long it waited for locks, and how many rows it read to return how many.
Drop the file on this page and the board shows it: query fingerprints ranked by total time (a Pareto chart), the rows-examined-to-rows-sent ratio per fingerprint, lock time, and a "look first" line for the worst full-scan query. The one-liners below answer the same questions on the server.
What gets written
A statement is written when all of these hold:
- It is not an administrative statement (ALTER TABLE, ANALYZE TABLE, CREATE INDEX, OPTIMIZE TABLE…), or
log_slow_admin_statementsis enabled. - It took at least
long_query_timeseconds, orlog_queries_not_using_indexesis enabled and it used no index for row lookups. - It examined at least
min_examined_row_limitrows. - It was not suppressed by
log_throttle_queries_not_using_indexes.
long_query_time defaults to 10 seconds, can be as low as 0, and accepts microsecond resolution. The log is off by default. A minimal configuration:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_output = FILEDetails that matter when you read the file:
- The time to acquire the initial locks is not counted as execution time.
- A statement is written after it finished and released its locks, so the order in the file can differ from the order of execution.
- Statements that fail to parse (syntax errors) are not written.
- Passwords in statements are rewritten so they do not appear in plain text.
log_timestampssets the time zone of the timestamps in the file.
One entry, line by line
# Time: 2026-10-18T10:41:02.551000Z
# User@Host: report[report] @ [10.0.3.5] Id: 5102
# Query_time: 12.880415 Lock_time: 0.412003 Rows_sent: 1 Rows_examined: 9120400
SET timestamp=1792320062;
SELECT COUNT(*) FROM order_items WHERE created_at >= '2026-10-01';| Line | What it holds |
|---|---|
# Time: | When the entry was written. |
# User@Host: | Account, client host or address, and the connection id. |
# Query_time: | Execution time in seconds. |
Lock_time: | Time spent acquiring locks, in seconds. |
Rows_sent: | Rows sent to the client. |
Rows_examined: | Rows examined by the server layer, not counting work inside the storage engine. |
SET timestamp= | Unix time at which the statement began executing. |
| statement | The SQL text, possibly on several lines, ending with a semicolon. A use db; line appears when the default database changed. |
The entry above read 9.1 million rows to return one, held a lock for 0.4 s and ran for 12.9 s. That ratio is the first thing to look at.
Extra fields with log_slow_extra
With log_slow_extra enabled, the # Query_time line gains per-statement counters: Thread_id, Errno, Killed, Bytes_received, Bytes_sent, the handler reads (Read_first, Read_last, Read_key, Read_next, Read_prev, Read_rnd, Read_rnd_next), sort counters (Sort_merge_passes, Sort_range_count, Sort_rows, Sort_scan_count), Created_tmp_disk_tables, Created_tmp_tables, Start and End. A file can mix lines with and without them; parsers tell them apart by field count. The one-liners below only use the first four fields, so they work either way.
How to read it
| Signal | Usually means | Next step |
|---|---|---|
| Rows_examined far above Rows_sent | The statement scans to find a few rows: missing or unusable index, or a filter on an unindexed column. | EXPLAIN the statement; look at the WHERE and ORDER BY columns. |
| Lock_time a large part of Query_time | Waiting on other transactions rather than doing work. | Find what held the lock at that time: long transactions, bulk updates, DDL. |
| Same statement shape, many entries | One query pattern dominates total time even if each run is moderate. | Group by fingerprint and sum Query_time; fix the top one first. |
| Entries bunched in a few minutes | A load spike, a batch job or contention event rather than a constantly slow query. | Line the times up with deploys, cron jobs and the web server log. |
Grouping by statement shape and adding up Query_time is what slow log summarizers do; MySQL ships mysqldumpslow for exactly this. A query that takes 0.8 s but runs 50,000 times a day matters more than one 30-second report.
Shell one-liners for the slow query log
The # Query_time line splits into fields as $3 = Query_time, $5 = Lock_time, $7 = Rows_sent, $9 = Rows_examined. All commands were run against a sample file with several entries.
How many statements are in the file?
grep -c '^# Query_time' slow.logHow many ran longer than one second?
awk '/^# Query_time/ && $3 > 1' slow.log | wc -lStatement count and total execution time.
awk '/^# Query_time/ {s += $3; n++} END {printf "%d statements, %.1f s total\n", n, s}' slow.logSlowest statements with the first line of their SQL.
awk '/^# Query_time/ {qt = $3; next} /^(#|SET timestamp|use )/ {next} qt != "" {print qt, $0; qt = ""}' slow.log | sort -rn | headRows examined per row sent, worst first.
awk '/^# Query_time/ && $7 > 0 {printf "%d %s/%s\n", $9/$7, $9, $7}' slow.log | sort -rn | headStatements with more than 0.1 s of lock time.
awk '/^# Query_time/ && $5 > 0.1 {print $5, $3}' slow.log | sort -rnWhich accounts produce slow statements.
awk '/^# User@Host/ {print $3}' slow.log | sort | uniq -c | sort -rnWhich client addresses produce slow statements.
grep '^# User@Host' slow.log | grep -oE '\[[0-9.]+\]' | sort | uniq -c | sort -rnGroup statements by the shape of their first line: literals replaced by ? and N.
awk '/^SET timestamp/ {getline; print}' slow.log | sed -E "s/'[^']*'/?/g; s/[0-9]+/N/g" | sort | uniq -c | sort -rn | headEntries per hour (UTC unless log_timestamps says otherwise).
grep '^# Time:' slow.log | cut -c9-21 | uniq -c
FAQ
What is the difference between Query_time and Lock_time?
Query_time is the execution time; Lock_time is the time spent acquiring locks. The time to acquire the initial locks is not counted as execution time.
Why is a fast query in the slow log?
Either log_queries_not_using_indexes is on and the query used no index for row lookups, or long_query_time is set very low (it can be 0, which logs everything).
Why are entries out of order?
MySQL writes a statement after it has finished and released its locks, so a long statement that started early is written after shorter ones that started later. Use SET timestamp for the start time.
What does a high Rows_examined to Rows_sent ratio mean?
The server read many rows to return a few, typically a full or wide scan because no suitable index exists. Check the statement with EXPLAIN.
Can I turn the slow log on without a restart?
Yes. slow_query_log and slow_query_log_file are global system variables that can be set at runtime; setting slow_query_log to 1 enables it.
Does the slow log contain passwords?
Passwords in statements are rewritten so they do not appear literally. The SQL text and literal values otherwise do appear, which is why analysing it locally matters.