WordPress performance issues are annoying to diagnose because the symptoms – slow page loads, high server CPU – don’t tell you much about the cause. Is it a slow database query? A plugin making HTTP calls on every page load? PHP taking forever to render a template? Without the right tool, you’re guessing.

Query Monitor is my first stop whenever I’m investigating a slow WordPress site. It’s a free plugin that adds a debug bar to the admin toolbar with detailed breakdowns of everything that happened during the request. Here’s how I use it.

Installation and setup

Install from the WordPress plugin directory like any other plugin. Activate it and you’ll see a new toolbar item showing the page’s query count and total time. Click it and a panel opens at the bottom of the screen.

By default, Query Monitor only shows output to users who are logged in as admins. You can set a cookie to enable it for a specific session without being logged in, which is useful when you want to profile the front-end experience of a non-admin user. There’s a section in the plugin settings that explains how to set that cookie.

One thing to know before you start: Query Monitor adds some overhead itself. The numbers you see are slightly higher than what a real visitor experiences. Use it to identify relative problems – a query taking 200ms is a problem whether the baseline is 50ms overhead or not.

Reading the Queries panel

This is where most performance investigations start. The Queries panel lists every database query that ran during the request, with the SQL, duration, caller (which function called it), and component (which plugin or theme).

What to look for:

  • Duplicate queries. Query Monitor highlights these in orange. Seeing the same query run 30 times usually means something is fetching post data in a loop without caching results. Classic N+1 problem – for each post in a list, code is running a separate query to fetch related data instead of loading everything in one query upfront.
  • High duration queries. Sort by duration. Anything above 50ms is worth investigating. Look at the SQL – is there a WHERE clause without an index? Are you querying on post meta keys that aren’t indexed?
  • Unexpected callers. If a query shows up with a caller from a plugin you haven’t thought about in months, that’s a flag. Some plugins run heavy queries on every page load unconditionally.

The Queries by Component breakdown is useful for blame assignment – it groups query counts and total time by plugin or theme. I’ve found plugins responsible for 80% of queries on sites that were visibly slow.

The Hooks panel

If you’ve read up on how hooks work in WordPress, you’ll appreciate this panel. It shows every action and filter that fired during the request, how many callbacks were attached, and the total time spent in those callbacks.

This is where you find hooks doing expensive work on every request. I once found a plugin that had attached a callback to the_content filter that was running a remote HTTP request to fetch translation data – on every single page load, for every post. The Hooks panel made it immediately visible: one filter callback, 800ms duration.

You can also use the Hooks panel to understand execution order when you’re writing your own hooks. It lists priorities alongside callback names, so you can see exactly where your code is firing relative to everything else.

HTTP API Calls

WordPress has a built-in HTTP API (wp_remote_get, wp_remote_post, etc.) and Query Monitor tracks everything that goes through it. This panel shows the URL, method, response code, and duration of each outbound HTTP request.

This is often where the worst offenders hide. Plugins that check for updates on every admin page load, themes that pull in external font metrics, integrations that hit third-party APIs synchronously during the request lifecycle – they all show up here. A single blocking HTTP call can add 500ms or more to a page load if the external service is slow.

The fix is usually caching: wrap the HTTP call in a transient so it only fires once per hour (or day, depending on how fresh the data needs to be). Query Monitor helps you find the calls; fixing them is usually a matter of adding WordPress transients around the expensive operations.

Common findings and what to do about them

After running Query Monitor on a dozen slow sites, certain patterns come up repeatedly:

  1. A WooCommerce or membership plugin running 50+ queries per page. Check if object caching is enabled. Most of those queries are likely cache misses that a Redis or Memcached object cache would eliminate.
  2. A slider or gallery plugin loading 10+ scripts and stylesheets on every page, including pages that have no slider. These plugins often enqueue assets globally and only conditionally render. The fix is usually a plugin-specific setting or a filter to conditionally enqueue.
  3. An SEO plugin with a slow hook callback that rebuilds metadata on every request. Look at the PHP Errors panel too – sometimes a deprecated function warning is causing extra processing.
  4. Post meta queries without indexes. If you’re querying _wp_attached_file or custom meta keys on large tables, check whether adding a meta_key index helps. This often requires a database-level intervention.

Query Monitor won’t fix your site for you, but it removes the guesswork. Before it, I’d approach a slow WordPress site by disabling plugins one by one and timing the result – effective but time-consuming. Now I open Query Monitor, look at the three panels above, and have a reasonable diagnosis in five minutes. If you’re doing any serious WordPress development or debugging, install it before you need it.