Insights

    Why Is Magento Slow? A Diagnostic Checklist for Store and Admin

    By Simon Bumford, Founder of EveryHostLast updated 15 min read

    Magento is usually slow because the full page cache is off or being bypassed, the cache and sessions are not in Redis or Valkey, indexers or cron are not working properly, or the store is not in production mode. After those come heavy extensions, an unhealthy search service, a heavy theme, bot traffic and, last, a server that is too small. Work through the checklist below in order: the cheapest fixes are near the top, and a slow admin or a slow checkout has its own section.

    Work through it in order

    The diagnostic checklist

    Run the commands from your Magento root, as the user that owns the Magento files, and try any change on a staging copy first.

    1. Is the store in production mode? Run bin/magento deploy:mode:show.
    2. Are all cache types enabled? Run bin/magento cache:status and look for any type showing 0, especially full_page.
    3. Is the full page cache on Varnish, and is it being hit? Check the caching application in the admin and the hit rate in Varnish.
    4. Are the cache and sessions in Redis or Valkey, rather than on disk?
    5. Are the indexers valid and on Update by Schedule? Run bin/magento indexer:status and bin/magento indexer:show-mode.
    6. Is cron running? Run crontab -l and check the cron_schedule table.
    7. Is OpenSearch healthy and given enough memory?
    8. Is an extension doing too much work? Profile a slow page.
    9. Are images, JavaScript and the theme heavy?
    10. Are bots and crawlers taking capacity? Check the access log.
    11. Is the server simply too small? Only once the points above are sorted.

    Full page cache off or bypassed

    If the full page cache is off or bypassed, Magento builds every page from scratch, and in our experience this is the most common cause of a slow Magento store.

    The full page cache stores finished public pages, such as category, product and CMS pages, so most visitors never wait for PHP. Check it is enabled with bin/magento cache:status; the full_page line should show 1. For a live store, Adobe says "We strongly recommend you use Varnish in production". The built-in cache works, but Adobe calls it much slower. The setting is under Stores > Settings > Configuration > Advanced > System > Full Page Cache.

    A full page cache can be switched on and still do little. Two things to look for:

    • Uncacheable blocks. Adobe's frontend guide says "If any block in a layout is designated as uncacheable, the entire page is uncacheable." One extension that adds cacheable="false" to a layout block on a product or category page sends every visit to that page back to PHP. Search your custom code and extensions for it, for example grep -rn 'cacheable="false"' app/code app/design vendor. Adobe's advice is never to make catalog, product or CMS pages uncacheable.
    • A low hit rate. Varnish's own varnishstat tool shows cache hits against misses. A hit rate that stays low usually means pages are being marked uncacheable, the cache is being cleared too often, or URLs carry parameters that turn one page into many different cache entries.

    Customer-specific parts of a page, such as the basket and the customer's name, are not in the full page cache. Adobe's private content model loads them in the browser after the page arrives, so a cached page can still show the right basket. Checkout and the basket themselves are not cached at all; by default, Adobe says, "all pages are cacheable except the checkout pages". More on how this works in Varnish cache for Magento.

    Cache and session storage: Redis or Valkey

    Magento's cache and customer sessions should sit in an in-memory store, Redis or Valkey, rather than in files on disk.

    On current Magento releases, Adobe requires Valkey rather than Redis for the cache: from 2.4.9, and from the patch releases after 2.4.5-p16, 2.4.6-p14, 2.4.7-p9 and 2.4.8-p4. Older releases use Redis. Adobe recommends keeping the default cache, the page cache and sessions apart, using separate databases or instances, so that clearing one does not empty the others. See Valkey for Magento and Redis and OpenSearch for Magento.

    Redis vs Varnish: which does Magento 2 need?

    Both, because they do different jobs. Varnish sits in front of Magento and serves whole public pages without running PHP. Redis or Valkey sits behind Magento and holds its internal cache, such as configuration and layout, plus customer sessions. One does not replace the other.

    Full page cache in Redis or Valkey

    Magento can store its built-in full page cache in Redis, or Valkey on newer versions, instead of in files. That is better than files, but it is still Magento's built-in cache, and Adobe's recommendation for production is Varnish. Redis or Valkey for the page cache suits stores that cannot run Varnish.

    Redis session locking

    PHP locks a customer's session while one request uses it, so a second request from the same visitor waits. That protects session data, but on pages that fire several requests at once, especially in the admin, the waits add up. Adobe documents settings for this: the maximum number of processes that can wait for one session's lock, how long frontend and admin requests wait before breaking the lock, and an option to disable locking entirely. On Redis they are set with flags such as --session-save-redis-max-concurrency and --session-save-redis-disable-locking; from 2.4.9 the flags use valkey in place of redis. Changing them is a trade-off between speed and session safety, so test on staging and change one thing at a time.

    How to flush the Redis or Valkey cache

    Use Magento's own command: bin/magento cache:flush empties the cache storage Magento is configured to use. Adobe's debugging guide also shows flushing one Redis database directly with redis-cli -n <db_number> FLUSHDB, and labels redis-cli FLUSHALL as flushing the cache and sessions; it marks both "do not run on production environments". In our experience, a FLUSHALL on an instance that also holds sessions signs every customer and admin user out. On Valkey the tool is valkey-cli.

    Indexers on the wrong mode

    Indexers on "Update on Save" make every admin save slower and can load the database at busy times; "Update by Schedule" moves the work into the background.

    Magento's indexers turn your catalogue, prices and stock into fast lookup tables. On Update on Save (realtime), each change is indexed immediately as it is saved. On Update by Schedule (schedule), changes are logged and cron indexes them in the background. Adobe advises: "Set the indexers to Update on Schedule for large sites, and sites with frequent updates and heavy traffic." Since 2.4.8, Update by Schedule is the default.

    bin/magento indexer:status
    bin/magento indexer:show-mode
    bin/magento indexer:set-mode schedule
    bin/magento indexer:reindex

    Adobe recommends putting the store into maintenance mode and pausing cron before you change indexer modes, so plan it for a quiet window. One version catch: before 2.4.8, the Customer Grid indexer could only use Update on Save. From 2.4.8 it supports both modes.

    Update by Schedule depends entirely on cron. If cron stops, the index falls behind, and prices, stock or new products stop updating on the store front.

    For every indexer command and how to fix stuck indexes, see Magento 2 reindex and indexers.

    Asynchronous indexing in Magento 2

    "Asynchronous indexing" in Magento usually means one of two things. The first is Update by Schedule, above. The second is a separate setting for the admin's order, invoice, shipment and credit memo grids: with asynchronous grid indexing on, placing an order no longer waits for those grids to update, and cron updates them shortly after. In production mode the Developer tab that holds this setting is hidden, so set it from the command line:

    bin/magento config:set dev/grid/async_indexing 1

    Cron must be running for the grids to update.

    Cron not running or stuck

    If Magento cron is not running, indexes go stale, emails and queued jobs pile up, and the store slowly drifts out of date without an obvious error.

    To check cron, Adobe suggests looking at the crontab as the Magento file system owner and at the cron_schedule table:

    crontab -l
    bin/magento cron:install

    crontab -l should show Magento's entries; if it doesn't, bin/magento cron:install adds them. Then look at recent jobs in the database:

    SELECT job_code, status, scheduled_at, executed_at, finished_at
    FROM cron_schedule
    ORDER BY scheduled_at DESC
    LIMIT 20;

    The status column shows each job's state: pending, running, success, missed or error. Lots of missed jobs mean cron isn't firing often enough or a job is overrunning. Jobs stuck on running for hours usually mean a job died part way through; Adobe has a knowledge base article on clearing them. Errors show the message in the same table. Adobe gives var/log/cron.log as the default cron log, and the crontab that cron:install writes sends its output to var/log/magento.cron.log.

    You can run cron by hand to test it, for example bin/magento cron:run --group=index for the indexing jobs. Cron also restarts Magento's message queue consumers through the consumers_runner job, which bulk actions and some asynchronous operations rely on.

    For a full walk-through, see Magento 2 cron not running?

    Developer mode in production

    A live store should run in production mode; Adobe says production mode "has better performance because static view files are populated in the pub/static directory and because of code compilation."

    bin/magento deploy:mode:show
    bin/magento deploy:mode:set production

    Switching to production mode compiles code and deploys static files, so the store goes into maintenance while it runs. Do it on staging first and expect errors that developer mode was hiding.

    Heavy or badly written extensions

    Extensions are the usual cause when the cache and server are healthy but certain pages are still slow.

    Find out where the time goes before removing anything. Magento has a built-in profiler:

    bin/magento dev:profiler:enable html
    bin/magento dev:profiler:disable

    It records how long each part of a page takes to build. Use it on staging, not on the live store, and switch it off afterwards. An application performance monitoring (APM) tool does the same job continuously in production, showing the slowest transactions, database queries and external calls. The database's slow query log is the other place to look. Common culprits are extensions that run heavy queries on every page, call external services while the page waits, observe busy events, or make blocks uncacheable.

    On staging, disabling suspect modules one at a time with bin/magento module:disable Vendor_Module confirms the culprit. The fix itself is a code change for your developer or the extension's vendor.

    OpenSearch sizing and health

    Catalogue search and layered navigation run through OpenSearch, so an unhealthy or memory-starved search service slows category pages and search results.

    Check the cluster's health from the server with curl -s 'localhost:9200/_cluster/health?pretty' (adjust the host and port to your setup). OpenSearch defines red as at least one primary shard unassigned, so some data can't be reached. Yellow means some replica copies are unassigned, which on a single-server setup usually just means there is no second node to hold them. Beyond health, OpenSearch needs its own memory: on a small server it competes with PHP and the database, and it is often left on default settings that don't suit the catalogue.

    OpenSearch vs Elasticsearch for Magento 2

    OpenSearch is the open-source search engine that grew out of Elasticsearch, and it is now Adobe's direction for Magento. Adobe's on-premises requirements list only OpenSearch 3 for Magento 2.4.9. For 2.4.8 the requirements table still lists Elasticsearch 8, but Adobe's 2.4.8 release notes say its Elasticsearch modules are deprecated. A store planning to upgrade should move to OpenSearch. More in Redis and OpenSearch for Magento.

    Images, JavaScript and the theme

    Even a fast server can't make a heavy front end feel quick, because much of what visitors notice happens in the browser.

    Oversized images, large JavaScript bundles, web fonts and third-party tags such as chat, reviews and tracking all slow the page down after the server has done its part. Magento's default Luma theme loads a lot of JavaScript. Hyvä is a lighter front end built to reduce that; see our guide to Magento Hyvä theme hosting. For how this affects Core Web Vitals, see Magento performance optimisation. For a CDN in front of the store, we recommend Cloudflare.

    Bots and crawler floods

    Aggressive crawlers and bots can take a large share of a server's capacity, and they tend to hit the pages the cache can't help with.

    Search results are never cached, and filtered category URLs come in endless combinations, so most of them are not in the cache. A crawler working through them lands on PHP almost every time. Look at the busiest IP addresses and user agents in your web server's access log, for example:

    awk '{print $1}' access.log | sort | uniq -c | sort -rn | head

    Well-behaved crawlers follow robots.txt; abusive ones don't, and have to be blocked at the server or at a CDN. Our guide on how to block AI crawlers on Magento 2 covers the rules. On EveryHost servers, Sentinel reads the server's logs and blocks abusive sources at the server firewall; it is not a web application firewall or a CDN.

    The server is too small

    Upgrade the server only once the points above are sorted; if CPU or memory still stays high under normal traffic, the store has outgrown it.

    Signs include the PHP-FPM log warning that the pool has reached its maximum number of children, the server using swap, OpenSearch running short of memory, and slowdowns that follow traffic rather than any one page. A bigger server buys little if the cache is being bypassed or an extension is the bottleneck, so measure first. Our Magento server calculator gives a starting point.

    Why the Magento admin is slow

    The Magento admin is never served from the full page cache, so it shows every database, indexer, session and extension problem directly.

    When only the admin panel is very slow, check these first:

    • Indexers on Update on Save, which make every product save wait for reindexing. Move them to Update by Schedule.
    • Synchronous grid indexing, which makes orders and the sales grids slower. Turn on asynchronous grid indexing.
    • Session locking, when several admin requests from the same user queue behind one another.
    • Large grids. Grids showing hundreds of rows, or many columns from extensions, run heavy queries. Show fewer rows and remove columns you don't use.
    • Cron and message queues. Bulk actions, such as mass attribute updates, run through message queue consumers that cron starts. If cron is down, they never finish.
    • Admin extensions. Some extensions add dashboards, notifications or checks to every admin page. The profiler shows them.

    Why Magento checkout is slow

    Checkout is never served from the full page cache, so it depends on PHP, the database, sessions and any payment, shipping or tax services it calls while the customer waits.

    A slow checkout with a fast homepage is normal, and fixing it means looking at the logged-in journey rather than the cached pages. We cover this in detail, including how it behaves under peak load, in Magento checkout speed at peak.

    How to clear Magento cache

    Use bin/magento cache:clean for everyday cache clearing, and bin/magento cache:flush only when cleaning hasn't fixed the problem.

    bin/magento cache:clean
    bin/magento cache:flush

    The difference, in Adobe's words: "Cleaning a cache type deletes all items from enabled Commerce cache types only", while "Flushing a cache type purges the cache storage, which might affect other processes" using the same storage. Adobe suggests you flush only if you have "already tried cleaning the cache" and still have problems. You can name cache types, for example bin/magento cache:clean full_page. In the admin, the same actions are under System > Cache Management.

    When Varnish is set up with Magento's purge settings (bin/magento setup:config:set --http-cache-hosts=...), Adobe says that "when you clean, flush, or refresh the Commerce cache, Varnish purges as well". There is no need to restart Varnish. If the cache uses Redis or Valkey, use these commands rather than flushing the Redis or Valkey database by hand, for the session reason above.

    Summary: symptom, cause and fix

    SymptomLikely causeWhere to checkFix
    Every page slow, even repeat visitsFull page cache off or on the built-in cachebin/magento cache:status; Stores > Configuration > Advanced > System > Full Page CacheEnable full_page and use Varnish
    Some product or category pages always slowA block marked cacheable="false"Layout XML in custom code and extensionsRemove it or move the content to private content; developer fix
    Low Varnish hit rateUncacheable pages, frequent cache clears, tracking parametersvarnishstatFind the cause before adding capacity
    Slow pages under load, sessions or cache on diskNo Redis or Valkeyapp/etc/env.phpMove cache and sessions to Redis or Valkey
    Admin requests queue behind each otherSession lockingSession settings in app/etc/env.phpTune locking settings on staging
    Admin saves very slowIndexers on Update on Savebin/magento indexer:show-modebin/magento indexer:set-mode schedule
    Prices, stock or new products not updatingCron not running or stuckcrontab -l; cron_schedule table; var/log/cron.logbin/magento cron:install; clear stuck jobs
    Orders and sales grids slowSynchronous grid indexingdev/grid/async_indexingbin/magento config:set dev/grid/async_indexing 1
    Whole store sluggish, errors shown in detailDeveloper modebin/magento deploy:mode:showbin/magento deploy:mode:set production on staging first
    Certain pages slow with a healthy cacheHeavy extensionProfiler, APM tool, slow query logDeveloper or vendor fix
    Search and category filters slowOpenSearch unhealthy or short of memoryCluster health; server memoryGive OpenSearch the memory it needs
    Fast server, slow-feeling pagesImages, JavaScript, theme, third-party tagsBrowser developer tools; Core Web VitalsLighter theme, smaller images, fewer tags
    Load spikes not matched by salesBots and crawlersWeb server access logrobots.txt, server-side blocking, a CDN
    High CPU or memory after all the aboveServer too smallPHP-FPM log, swap, monitoringMove to a bigger server
    Checkout slow, rest of store fineUncached checkout, sessions, third-party callsLogged-in journey under loadSee the checkout speed guide

    Need a hand?

    If you've worked through the checklist and your store is still slow, we can help. We tune the server layer on our servers in our London data centre, tell you honestly what is server and what is code, and pass code findings to your developer. See Magento performance optimisation and our plans and prices.

    Frequently asked questions

    Run bin/magento cache:clean from your Magento root, or go to System, then Cache Management in the admin. Cleaning removes items from Magento's enabled cache types only. If that does not fix the problem, bin/magento cache:flush empties the whole cache storage, which can affect anything else using it. If Varnish is set up for Magento, it is purged at the same time.

    The admin is never served from the full page cache, so it shows database, indexer and session problems directly. The usual causes are indexers on Update on Save, synchronous grid indexing, session locking, very large grids, cron not running, and extensions that add work to every admin page.

    Adobe recommends Update by Schedule for large sites and sites with frequent updates and heavy traffic, and it has been the default since Magento 2.4.8. It moves indexing into the background through cron, so cron must be running. Before 2.4.8, the Customer Grid indexer could only use Update on Save.

    Run crontab -l as the user that owns the Magento files and check Magento's entries are there; if not, bin/magento cron:install adds them. Then check the cron_schedule table: recent jobs should show success, and many missed jobs, errors or jobs stuck on running for hours mean something is wrong. The cron log is in var/log.

    Only if the server is genuinely short of capacity. If the full page cache is being bypassed, indexers are on the wrong mode, cron has stopped or an extension is the bottleneck, a bigger server costs more without fixing much. Work through the checklist first, then upgrade if CPU or memory stays high under normal traffic.

    Still slow after the checklist?

    Tell us what feels slow and we will tell you honestly whether it is the server, the code or the theme.