Databases & NoSQL

MySQL Performance Optimization: Diagnosing & Fixing Slow Queries

By the Domain India teamPublished 8 min read
Knowledge base article
Contents (7 sections)

A slow database makes every page slow, and on shared hosting it also holds PHP requests open until your account runs into its limits. Most slow queries have the same few causes: a missing index, a query that reads far more rows than it returns, or a table that has grown for years without clean-up. This guide shows how to find the slow query, read EXPLAIN, fix it with the right index, and which server settings matter only when you run your own server.

Key takeaways

Find the slow query first (Query Monitor on WordPress, your own timing logs, or the slow query log on your own server), then run EXPLAIN on it. If it shows type: ALL or a large rows number, add an index that matches the WHERE and ORDER BY columns. Select only the columns you need and page large results. On shared hosting you tune queries and indexes, not the server; my.cnf settings such as the buffer pool apply only on your own VPS. The old query cache no longer exists in MySQL 8.

1. Where the time actually goes

A query is slow when it examines many rows to return a few. A table with 500,000 orders and no index on customer_id means MySQL reads all 500,000 rows every time someone opens "My orders". The fix is almost never more hardware; it is letting MySQL jump straight to the rows it needs.

Other common causes:

  • Sorting without an index (ORDER BY on an unindexed column), which shows up as Using filesort.
  • SELECT * on wide tables, pulling text and blob columns nobody displays.
  • N+1 queries: one query for a list, then one more query per row, often hidden inside a plugin or ORM loop.
  • Bloated tables, such as a WordPress wp_options table full of autoloaded data, or years of revisions and expired transients.
  • Lock waits, where one long write blocks everyone reading the same rows.

2. Find the slow queries

Where you runHow to find slow queries
WordPress, any hostingThe free Query Monitor plugin lists every query on a page, its time and the plugin that ran it
Your own PHP code, any hostingTime each query in your code and log anything over, say, 0.5 seconds
Shared hosting, phpMyAdminRun the suspect query in the SQL tab; it reports the time taken. Run EXPLAIN on it there too
Your own VPS or serverTurn on the slow query log (section 6) and summarise it

SHOW PROCESSLIST; (or SHOW FULL PROCESSLIST;) shows what is running right now. On shared hosting you see only your own database user's connections, which is enough to spot a query stuck for many seconds.

3. Read EXPLAIN

Put EXPLAIN in front of any SELECT to see how MySQL plans to run it:

sql
EXPLAIN SELECT id, total, created_at
FROM orders
WHERE customer_id = 42
ORDER BY created_at DESC
LIMIT 20;

The columns that matter:

ColumnGood signBad sign
typeconst, eq_ref, ref, rangeALL (full table scan), index on a big table
keyThe index you expectNULL: no index used
rowsClose to the number of rows returnedThousands or millions for a small result
ExtraUsing index, Using whereUsing filesort, Using temporary

On MySQL 8.0.18 and later you can run the query for real and see actual times per step (MariaDB uses ANALYZE SELECT ... for the same job):

sql
EXPLAIN ANALYZE SELECT id, total FROM orders WHERE customer_id = 42;

EXPLAIN ANALYZE executes the query, so don't use it on a slow UPDATE or DELETE on a live site.

4. Fix it with the right index

Check what already exists:

sql
SHOW INDEX FROM orders;

Then add an index that matches how the query filters and sorts. For the query above, one composite index covers both the WHERE and the ORDER BY:

sql
ALTER TABLE orders ADD INDEX idx_customer_created (customer_id, created_at);

Rules that hold in practice:

  • Column order matters. Put the columns you compare with = first, then the range or sort column. An index on (customer_id, created_at) helps WHERE customer_id = ? ORDER BY created_at, but not a query that filters only on created_at.
  • One good composite index beats several single-column ones for multi-column filters.
  • Prefix indexes for long text. ADD INDEX idx_email (email(50)) keeps the index small. Prefix indexes can't satisfy an ORDER BY on that column.
  • LIKE '%word%' can't use a normal index. For word search, use a FULLTEXT index with MATCH ... AGAINST.
  • Don't index everything. Each index slows inserts and updates and uses disk. Remove indexes that EXPLAIN never picks.
Adding an index to a big table takes time

On a table with millions of rows, ALTER TABLE can run for minutes and slow the site while it works. Export the table in phpMyAdmin first and run it at a quiet hour.

5. Write lighter queries

  • Select only the columns you use: SELECT id, name instead of SELECT *.
  • Page large results with LIMIT. For deep pages, use keyset pagination (WHERE id < last_seen_id ORDER BY id DESC LIMIT 20) instead of a large OFFSET, which still reads every skipped row.
  • Replace N+1 loops with one query using JOIN or WHERE id IN (...).
  • Don't wrap indexed columns in functions. WHERE DATE(created_at) = '2026-09-01' can't use an index; WHERE created_at >= '2026-09-01' AND created_at < '2026-09-02' can.
  • Use prepared statements (PDO or mysqli). They protect against SQL injection, and the plan stays predictable.
  • Clean up. On WordPress, remove old revisions, spam comments and expired transients, and check wp_options for large autoloaded rows. Take a backup first.

6. Server settings: only on your own VPS or server

Everything in this section applies to a MySQL or MariaDB server you manage, such as your own VPS. On shared hosting the database server is shared by many accounts, so you can't edit my.cnf, restart MySQL or read the server's slow query log. Tune your queries and indexes instead, and ask support if you think something is wrong on the server side.

Slow query log. Add under [mysqld] (/etc/my.cnf on AlmaLinux, /etc/mysql/mysql.conf.d/mysqld.cnf on Ubuntu with MySQL), make sure the log folder exists and is owned by the mysql user, and restart the service:

ini
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1

Summarise it with mysqldumpslow -s t /var/log/mysql/slow.log | head -30, or pt-query-digest from Percona Toolkit.

Settings worth checking:

SettingWhat it doesStarting point
innodb_buffer_pool_sizeMemory for cached data and indexes; the most important settingAbout 50–70% of RAM on a server that runs only the database; less if the web server shares it
innodb_log_file_size / innodb_redo_log_capacitySize of the redo log; larger smooths heavy writesLeave the default unless writes are heavy (MySQL 8.0.30+ uses innodb_redo_log_capacity)
max_connectionsMost connections at onceSize it to your app's real peak; each connection uses memory
tmp_table_size and max_heap_table_sizeIn-memory temporary tablesSet both to the same value, for example 64M

Change one setting at a time and measure. Copying an "optimised my.cnf" from the internet, written for someone else's RAM and workload, often makes things worse.

The query cache is gone

MySQL 8.0 removed the query cache completely, and query_cache_* lines stop MySQL 8 from starting. MariaDB still has it, but disabled by default because it serialises busy servers. Cache in your application instead: page caching for websites, and Redis or Memcached for data on your own VPS.

7. Running this on Domain India

Shared hosting (cPanel, DirectAdmin, Webuzo). Use phpMyAdmin in your control panel to run EXPLAIN and add indexes. Port 3306 is closed to outside connections on our shared servers, so desktop tools such as MySQL Workbench or DBeaver need an SSH tunnel. Jailed SSH access is available on every shared hosting plan (cPanel, DirectAdmin, Webuzo). It is off by default; ask support to enable it for your account. Login is with an SSH key. See securing MySQL access with SSH tunnels. If slow queries are pushing your account into its limits, check your resource usage, and for database errors see database troubleshooting.

VPS. Our VPS is self-managed with full root access, so every setting in section 6 is yours to tune.

VPS Starter
₹552.65/mo + GST
  • 1 vCPU
  • 2 GB DDR4 RAM
  • 64 GB NVMe SSD Storage
  • 2 TB Monthly Bandwidth
See plan details

App Platform. Every plan includes a managed PostgreSQL database, if you are building a new app rather than tuning an existing MySQL one.

How do I find which MySQL query is slow?

On WordPress, install the free Query Monitor plugin, which lists each query, its time and the plugin that ran it. In your own code, time each query and log the slow ones. On your own VPS, turn on the slow query log and summarise it with mysqldumpslow or pt-query-digest.

What should I look for in EXPLAIN output?

Look at type, key, rows and Extra. type ALL with key NULL means a full table scan. A rows value far larger than the rows you get back, or Using filesort or Using temporary in Extra, means the query needs a better index or a rewrite.

Which columns should I index?

Index the columns used in WHERE, JOIN and ORDER BY for your slowest, most frequent queries. For queries filtering on several columns, one composite index with the equality columns first and the sort or range column last usually works best.

Can I enable the query cache to speed up MySQL?

No. MySQL 8.0 removed the query cache entirely, and on MariaDB it is disabled by default because it slows busy servers. Use page caching for websites and an application cache such as Redis on your own server.

Can I change my.cnf or enable the slow query log on shared hosting?

No. The database server on shared hosting is shared by many accounts, so server settings are managed for everyone. You can still fix slow queries with EXPLAIN, better indexes and lighter queries in phpMyAdmin. For full control of MySQL settings, use a VPS.

Will a bigger hosting plan fix slow queries?

Rarely. A query that scans a whole table stays slow on any plan. Fix the index or the query first; upgrade only if the account still runs out of resources after that.

Ready to speed up your database? Work through my website is slow, connect safely with how to connect to the MySQL database, or compare VPS plans if you need full control of MySQL.

Need a hand with a slow database?

Send us the slow page, the query if you have it and when it happens, and we will help you find where the time goes.

Open a support ticket

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app
Fix Slow MySQL Queries: EXPLAIN, Indexes, Tuning