WordPress Slow Queries: Find and Fix Them

WordPress Slow Queries: Find and Fix Them

Database queries are the heartbeat of WordPress. Every page load sends queries to MySQL. But hidden among those queries are often the culprits killing your site’s performance: slow queries. This guide shows you exactly how to identify them, understand why they’re slow, and fix them permanently.

What Counts as a Slow Query?

MySQL’s default slow query threshold is 10 seconds. That’s far too generous. Here’s what actually matters:

  • Under 10ms: Generally not a concern
  • 10-100ms: Watch these if executed frequently
  • 100ms-1s: Definitely slow, needs investigation
  • Over 1s: Critical performance killer, fix immediately

The real metric isn’t query time alone — it’s query time x execution count. A query running in 0.05 seconds but executing 10,000 times per day contributes 500 seconds of total database load.

Enabling the MySQL Slow Query Log

MySQL Configuration

[mysqld]
slow_query_log = 1
long_query_time = 0.5
log_slow_admin_statements = 1
log_queries_not_using_indexes = 1
slow_query_log_file = /var/log/mysql/slow-query.log
  • slow_query_log = 1 — Enables logging
  • long_query_time = 0.5 — Logs queries over 0.5s (adjust to 0.1 for aggressive logging)
  • log_queries_not_using_indexes = 1 — Critical: catches queries without indexes even if fast

MariaDB Configuration

[mysqld]
slow_query_log = 1
long_query_time = 0.5
log_slow_admin_statements = 1
log_queries_not_using_indexes = 1
log_slow_verbosity = query_plan,explain
slow_query_log_file = /var/log/mysql/slow-query.log

The log_slow_verbosity = query_plan,explain is MariaDB-specific and gives you EXPLAIN output automatically in the log.

Reading Slow Query Log Output

# Time: 2026-02-06T14:23:45.123456Z
# User@Host: wordpress_user@localhost
# Query_time: 0.587293  Lock_time: 0.000042  Rows_sent: 1  Rows_examined: 150847
SELECT wp_posts.ID, wp_posts.post_title
FROM wp_posts
WHERE post_content LIKE '%example%'
AND post_status = 'publish'
AND post_type = 'post';

Key metadata:

  • Query_time: How long the query took (0.587s = 587ms)
  • Lock_time: Time waiting for locks (0 = no contention)
  • Rows_sent: Rows returned (1)
  • Rows_examined: Rows MySQL scanned (150,847)

In this example, MySQL scanned 150,847 rows to return 1 result. That’s terrible efficiency and a clear sign this query needs an index.

Using EXPLAIN to Understand Queries

EXPLAIN SELECT wp_posts.ID, wp_posts.post_title
FROM wp_posts
WHERE post_content LIKE '%example%'
AND post_status = 'publish'
AND post_type = 'post';
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows | Extra       |
|  1 | SIMPLE      | wp_posts | ALL  | NULL          | NULL | NULL    | NULL | 5438 | Using where |

The type column hierarchy from fastest to slowest:

  • system/const: Single row by primary key (excellent)
  • eq_ref: One row per outer row (excellent)
  • ref: Multiple rows with same indexed value (good)
  • range: Rows within a range using index (good)
  • index: Full index scan (okay)
  • ALL: Full table scan (worst — almost always the problem)

See type = ALL and key = NULL? Full table scan. The query examined all 5,438 posts. On large databases, this becomes catastrophically slow.

Common WordPress Slow Query Patterns

Pattern 1: Postmeta JOINs Without Indexes

SELECT wp_posts.ID
FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE wp_posts.post_type = 'post'
AND wp_postmeta.meta_key = 'product_color'
AND wp_postmeta.meta_value = 'blue';

Without indexes on wp_postmeta.meta_key and wp_postmeta.meta_value, MySQL scans the entire postmeta table. On WooCommerce sites with millions of product variants, this takes seconds.

Pattern 2: Options Table Full Scans

Unindexed wp_options queries scan every row. With thousands of options on mature sites, this adds up.

Pattern 3: Taxonomy Queries on Large Sites

Sites with thousands of products or large category hierarchies suffer from missing indexes on term_relationships.

Pattern 4: WooCommerce Multi-JOIN Queries

SELECT wp_posts.ID
FROM wp_posts
LEFT JOIN wp_postmeta AS pm1 ON (wp_posts.ID = pm1.post_id AND pm1.meta_key = '_price')
LEFT JOIN wp_postmeta AS pm2 ON (wp_posts.ID = pm2.post_id AND pm2.meta_key = '_stock_status')
WHERE wp_posts.post_type = 'product'
AND wp_posts.post_status = 'publish';

Each additional JOIN without indexes exponentially increases execution time.

Pattern 5: Search Queries with LIKE Wildcards

SELECT * FROM wp_posts
WHERE post_status = 'publish'
AND (post_title LIKE '%search-term%'
OR post_content LIKE '%search-term%')

The leading wildcard %search-term% prevents index usage. MySQL must scan every row.

Adding Database Indexes

Indexes transform slow queries into fast ones. Here are the most important indexes for WordPress:

-- Fix postmeta queries
ALTER TABLE wp_postmeta ADD INDEX meta_key (meta_key);
ALTER TABLE wp_postmeta ADD INDEX post_id_meta_key (post_id, meta_key);

-- Fix taxonomy queries
ALTER TABLE wp_term_relationships ADD INDEX term_taxonomy_id (term_taxonomy_id);

-- Fix post type and status queries
ALTER TABLE wp_posts ADD INDEX post_type_post_status (post_type, post_status);

-- WooCommerce specific compound index
ALTER TABLE wp_postmeta ADD INDEX post_id_meta_key_value (post_id, meta_key, meta_value(10));

Before adding indexes, check what exists:

SHOW INDEXES FROM wp_postmeta;

Don’t add duplicate indexes — that wastes disk space and slows INSERT/UPDATE operations.

Query Optimization Techniques

Full-Text Indexes for Search

ALTER TABLE wp_posts ADD FULLTEXT ft_content (post_content);

SELECT wp_posts.* FROM wp_posts
WHERE MATCH(post_content) AGAINST('keyword' IN BOOLEAN MODE)
AND post_status = 'publish';

Full-text indexes handle search queries 10-100x faster than LIKE on large datasets.

Object Cache for Frequent Queries

Instead of querying the database repeatedly, cache results in memory with Redis or Memcached. A single slow query executed 1,000 times per day becomes 1 database hit with object caching.

Transient Caching for Expensive Queries

$expensive_data = get_transient('my_expensive_query');

if (false === $expensive_data) {
    $expensive_data = $wpdb->get_results(
        "SELECT * FROM wp_posts
         INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
         WHERE wp_postmeta.meta_key = 'product_color'
         AND wp_postmeta.meta_value = 'blue';"
    );

    // Cache for 12 hours
    set_transient('my_expensive_query', $expensive_data, 12 * HOUR_IN_SECONDS);
}

return $expensive_data;

Plugin-Generated Slow Queries

Most slow queries on WordPress sites come from plugins, not core. Query Monitor shows every query and which code triggered it. Use mysqldumpslow for log analysis:

mysqldumpslow -s c -t 10 /var/log/mysql/slow-query.log

This shows the 10 most common slow queries. Copy each query, then search your plugin code to identify the source.

Monitoring Over Time

mysqldumpslow -s t -t 20 /var/log/mysql/slow-query.log > slow-queries-report.txt

Generate weekly reports of the 20 slowest queries by total time. Track these over weeks to catch degradation early.

Automated Slow Query Detection with WP Multi Tool

WP Multi Tool includes an automated slow query detection module that:

  • Automatically enables slow query logging with optimal thresholds
  • Parses your slow query log every hour
  • Identifies top problematic queries by impact (time x frequency)
  • Attempts to pinpoint the source plugin using code analysis
  • Recommends specific indexes or optimizations
  • Alerts you to new slow queries

The Action Plan

  1. Enable slow query logging with long_query_time = 0.5
  2. Let it run for 24-48 hours to capture realistic traffic
  3. Use mysqldumpslow to find the slowest queries by total time
  4. Run EXPLAIN on each slow query to understand the execution plan
  5. Check if relevant indexes exist; if not, add them
  6. Use Query Monitor to identify the source plugin
  7. Implement object caching for frequently executed queries
  8. Re-run analysis to verify improvements
  9. Set up ongoing monitoring

Database performance is often the most impactful lever. A site with perfectly optimized queries will feel fast regardless of other factors. Start here — find and fix your slowest queries. WP Multi Tool can automate slow query detection and alerting across your sites.

For broader database optimization, see WordPress Database Optimization: Complete Guide. For the full diagnostic framework, read Finding What Makes WordPress Slow.