Skip to content

Why is PrestaShop slow — 12 causes and how to diagnose them

Mateusz Bartocha

  • PrestaShop
  • performance
  • optimization
  • MySQL
  • Core Web Vitals

A slow store hurts conversion, worsens the user experience and makes good Core Web Vitals harder to reach. Before you spend money on a "speed booster", it pays to know what actually slows PrestaShop down. Here are the 12 most common causes we see in audits, and how to diagnose each of them.

First, decide: backend or front-end?

A "slow store" can mean slow HTML generation on the server, slow page rendering in the browser, or both at once. A high TTFB points the diagnosis toward the backend — PHP, MySQL, infrastructure and server configuration. A good TTFB with a poor LCP or INP points instead to the front-end — images, JavaScript, CSS and third-party scripts. This distinction saves hours of looking in the wrong place.

1. Unsuitable hosting (slow disk, insufficient RAM)

One of the more common and most underestimated causes. Shared hosting with high disk latency, restrictive CPU limits or little available memory may not keep up with a store that generates expensive queries and real traffic. The disk type (SSD vs NVMe) or the product count alone don't settle it — what matters is disk latency, random IOPS, host contention and the neighbours on a shared environment. A too-small InnoDB buffer pool increases storage reads and can worsen query latency.

How to diagnose: measure TTFB (server response time) multiple times, from a location close to the server, separately for cache hit and cache miss, and without extra redirects. Bear in mind that a publicly measured TTFB also includes DNS, TCP/TLS, proxy/CDN and the network — it is not pure PHP/MySQL time, so measure as close to the origin as you can, compare similar pages (p50/p95), and read the application time itself from the profiler or an APM. Our rough warning sign is ~600 ms on a category page — a practical threshold from audits, not a standard; it depends on location and architecture. Also check disk IOPS and CPU saturation. Do not diagnose by "RAM usage" alone — Linux and MySQL deliberately use free memory for cache, so high usage by itself is not a problem.

2. An unoptimized MySQL database

PrestaShop accumulates data over time: the ps_connections, ps_guest, ps_cart, logs and stats tables can grow to millions of rows. Also worth checking is ps_configuration, loaded heavily while serving requests: its growth after dozens of installed and removed modules (orphaned rows) can add overhead, but the real impact depends on the version and how it is cached — confirm it by measurement, and do not delete rows blindly (back up first, as manual cleanup can break modules). The default schema does have indexes, but as tables grow so does the cost of the queries that scan large ranges, sort/aggregate, or miss a suitable index (typically module queries) — not all queries get proportionally slower.

  • Enable the slow query log, but do not read only the longest single entries — aggregate queries by fingerprint and look at total cost (e.g. pt-query-digest): a 50 ms query run 100,000 times costs more than one 2-second query.
  • Check the size of your largest tables — data and indexes together (SELECT table_name, data_length + index_length ... FROM information_schema.tables ...), not data_length alone.
  • Verify the InnoDB configuration (innodb_buffer_pool_size) against available memory.
  • Look for typical patterns: missing indexes on module tables, a separate SELECT per product (the N+1 pattern), expensive COUNT(*), large sorts and temporary tables, queries over combinations and filters.

3. Misconfigured cache (OPcache, Smarty, object cache)

Without OPcache, PHP reloads and compiles the code from scratch on every request. In PrestaShop, also make sure that forced template (Smarty) recompilation is disabled in production and that the compiled-template cache is active. This is one of the first things to check — the check is quick and a misconfiguration affects the whole application; it is very often simply set wrong.

The object cache does not always speed the store up. In Advanced → Performance (on PrestaShop 1.7/8/9) you usually get APC (APCu on PHP 7+) and Memcached — the exact list depends on the store version and the installed PHP extensions. Redis is not a standard object-cache backend in the panel (the core has no CacheRedis class) — it needs a dedicated module. On a single, fast server the extra layer may bring no noticeable gain, and when misconfigured it can even add latency. It matters at higher traffic, for expensive operations and in multi-server setups. Measure cache effectiveness and your query profile before enabling it.

How to diagnose: check not only whether OPcache is active (opcache_get_status), but also whether it is short on memory and script slots (opcache.memory_consumption, opcache.max_accelerated_files, the cached-scripts count, out-of-memory restarts) and whether you are looking at the right SAPI — PHP-FPM, not CLI. Also verify Smarty template compilation and the var/cache/prod directory. Do not enable the object cache "just in case" — match it to your architecture and traffic.

Expert tip

open_basedir quietly disables PHP's realpath cache

Here is a lesser-known setting that quietly costs performance. Many administrators do not realize that enabling PHP's open_basedir restriction disables the realpath cache — PHP effectively forces realpath_cache_size to 0 whenever open_basedir is active. With that cache off, PHP has to resolve filesystem paths from scratch for the thousands of include, require and file operations that every PrestaShop request performs, instead of reusing a cached result.

On a small site this is negligible. On a larger PrestaShop store — a deep directory tree, many modules, a big autoloaded codebase — that repeated path resolution (a flood of lstat system calls) becomes measurable overhead on every request. In a properly isolated environment — a dedicated PHP-FPM user per store, correct filesystem permissions, containers or virtual machines — you can disable open_basedir and instead size realpath_cache_size (and realpath_cache_ttl) appropriately, which can noticeably lower PHP execution time.

In our audits this typically lands around a 5–20% reduction in PHP execution time, or roughly 50–200 ms lower TTFB on some stores — real-world observations, not a guaranteed result. It is not a universal recommendation. Disabling open_basedir on poorly isolated shared hosting can weaken the security boundary between sites on the same server, so the hosting architecture should first be reviewed to confirm proper isolation before this setting is changed. As with every change here, measure PHP time and TTFB before and after — this is exactly the kind of setting our performance audits verify and safely implement where the environment allows it.

4. Excessive and poorly written modules

Modules are one of the most common sources of "hidden" load. Rich filters, "recently viewed", recommendations or counters can generate hundreds of SQL queries on every page and load their own CSS/JS across the whole store.

How to diagnose: enable the profiler (set _PS_DEBUG_PROFILING_ to true in config/defines.inc.php) only in a controlled environment — the profiler exposes SQL queries, paths and configuration data, so never leave it on public staging or production. Then look at the SQL query count and load time per hook. More important than the raw query count is their total time, repetition and cost under load — a module responsible for a large share of PHP time, or running repeated, scanning queries, is a candidate for optimization, replacement or removal (hundreds of queries on a single page is a warning sign).

5. Cron jobs, integrations and background processes

Product imports, stock synchronization, ERP and marketplace integrations, thumbnail regeneration, search indexing and bulk price updates can hit PHP, MySQL and the disk all at once. The store then slows down only at certain hours, so a one-off audit easily misses it.

How to diagnose: correlate the hours of slowdowns with the cron schedule, integration logs and the CPU, I/O and MySQL query charts. Running jobs off-peak helps, but it is not a universal cure (multi-market stores, continuous stock sync): limit concurrency, split work into smaller batches, queue it, add idempotency and retry with backoff, and guard against several copies of the same process running in parallel (a lock).

6. Bots and excessive automated traffic

A store can be fast under normal traffic yet slow down because of price comparison engines, AI bots, SEO crawlers, marketplace integrations and scrapers. The most expensive URLs are filters, search, sorting and category combinations — each visit can generate heavy SQL queries.

How to diagnose: analyze access logs by IP, User-Agent, request count and most-visited URLs; check whether bots hit dynamic pages, the API, search and infinite filter combinations. Before you start blocking, distinguish the traffic classes (legitimate crawler, business partner, API integration, monitoring, malicious scraper) — each needs a different response: work out whether the traffic is business-required, whether the bot respects robots, whether it uses the API, whether its rate can be limited, and whether it has a stable IP or authentication. Only then reach for Cloudflare, rate limiting, cache rules and correct indexing management. Remember: robots.txt is not a security control — honest bots respect it, malicious ones need not.

7. A heavy front-end (images, render-blocking CSS/JS)

Large, uncompressed images and render-blocking scripts wreck Core Web Vitals — especially LCP (time to render the largest element) and INP (responsiveness to interaction). This directly affects the perceived speed, and Core Web Vitals are one of many signals Google systems take into account.

  • How to diagnose: measure the page in PageSpeed Insights, but separate the lab data (Lighthouse: TBT, the LCP candidate, render-blocking resources) from the field data in CrUX (real Chrome-user measurements: LCP, INP, CLS). Assess INP from field data — a lab run without real interactions will not measure it, and TBT is only a proxy for it.
  • Fix: first identify the actual LCP element (it can be text, not an image). Convert images to WebP/AVIF and enable lazy loading only below the fold — do not lazy-load the image that is the LCP element, and consider fetchpriority="high" for it selectively. Explicit width/height mainly prevents CLS, it does not speed up LCP.
  • Fix: defer and trim unnecessary JavaScript and third-party widgets/marketing scripts (key for INP); add font-display to your fonts. Which fixes apply depends on the resource waterfall and the real LCP element — it is not one checklist to enable wholesale.

web.dev: Interaction to Next Paint (INP) — lab vs field measurement

8. No effective HTTP cache, compression and (for international traffic) CDN

For a store serving mainly one market, with a server in a nearby region, good cache headers, HTTP/2 or HTTP/3, a fast origin and fewer resources often matter more than a CDN. The latency benefit of a CDN is usually larger for users far from the origin, but a CDN also offloads and protects the server (cache, traffic-spike absorption, TLS termination, bot filtering) for domestic traffic too. Compression (Brotli/gzip) greatly reduces the transfer of text assets — HTML, CSS, JS, JSON, SVG; already-compressed formats (JPEG, WebP, AVIF, PNG, WOFF2) gain little from it.

How to diagnose: check separately the cacheability and headers (Cache-Control, asset versioning), the compression (Content-Encoding), and the transfer and download time of static assets from different locations.

Practical tip: for many stores, the simplest way to offload the server is putting Cloudflare in front. Even the Free plan gives a global CDN, compression, HTTP/3, static-asset caching and basic bot filtering. Installing it will not fix slow code or a slow database, but it often usefully complements infrastructure optimization — what it gives you, where its limits are and which mistakes to avoid, we cover in a separate article.

Read: Cloudflare for PrestaShop — benefits and limits

9. Exhausted PHP-FPM process pool

Every dynamic PrestaShop request occupies one PHP-FPM worker. When all workers are busy, further requests wait in a queue — even if the server is not using all of its CPU or RAM — so the store stalls or returns 502/504 while looking idle. It is worth seeing this for what it usually is: a symptom, not the root cause. The pool fills up because something is making requests slow, and that something is normally one of the causes already covered — slow SQL, expensive modules, bots, external APIs or cron jobs. Hitting the pm.max_children limit is only evidence that the workers are busy; it does not say why.

That is why raising pm.max_children without finding the underlying cause usually just hides the problem — and can make it worse, since more concurrent workers mean more memory used and more parallel load on MySQL. Before touching the pool, correlate the signals: the "server reached pm.max_children" message and pool status (active processes, listen-queue length, the max_children-reached counter), the PHP-FPM slowlog (request_slowlog_timeout), request duration, MySQL activity (Threads_running), external API calls, bot traffic and the cron schedule. Only once you know what is keeping the workers busy should you size the pool — and never raise pm.max_children without calculating a single worker's memory footprint, or you risk swapping and processes being killed by the OOM Killer.

10. Debug mode and profiler left on in production

Debug mode (_PS_MODE_DEV_) left on after deployment turns on extra diagnostics, detailed error reporting and development-environment mechanisms, which can significantly increase the time and memory of every request. The profiler (_PS_DEBUG_PROFILING_) adds a separate, large measurement overhead on the front office and back office. This is a common, trivial, yet very costly mistake.

How to diagnose: verify _PS_MODE_DEV_ and _PS_DEBUG_PROFILING_ in config/defines.inc.php (and config/defines_custom.inc.php if it exists — the values set there take precedence). In production both must be disabled.

11. An old PrestaShop and PHP version

Unsupported, older PHP versions are not only a security risk — they also lack many performance improvements from newer releases. The real gain, however, depends on the store code, the modules and the OPcache configuration. Note: the PHP version is tied to the PrestaShop version (older PrestaShop will not run on the latest PHP), so bumping PHP usually requires a coordinated PrestaShop and module upgrade — a project, not a flag flip.

How to diagnose: check the PHP version (php -v) and the PrestaShop version in the back office, then verify which PHP your PrestaShop version supports. Do not upgrade PHP without testing theme, override and module compatibility. A newer PHP can improve performance, but the effect has to be measured on the specific store — sometimes the dominant problem remains SQL, an API or a module.

12. A bloated .htaccess file (thousands of redirects)

Apache reads the .htaccess file and recompiles its RewriteRule directives on every request (unlike the vhost configuration, where rules are compiled once and cached). If someone dropped thousands of unoptimized 301 redirects into .htaccess — after a URL migration or from an SEO module — every request runs sequentially through hundreds of regular expressions. That directly raises TTFB, the server response time.

How to diagnose: check the size and rule count of .htaccess (how many RewriteRule/Redirect lines) — the count alone, though, is only a signal; order, backtracking, the number of RewriteCond and how often rules match all matter too, so confirm the problem by measurement (compare TTFB with the full vs a slimmed-down .htaccess). The fix: move stable rules into the server configuration (vhost), where they compile once, and handle bulk redirects more efficiently — a server-level redirect map instead of a thousand regex lines. Note: on shared hosting or Plesk, vhost access is often unavailable — then at least reduce and simplify the rules. A plain Redirect (mod_alias) can be cheaper than a complex RewriteRule when no rewriting is needed, but it has different semantics (query strings, ordering) — verify them before swapping.

Apache: when (not) to use .htaccess files

Summary: measure, don't guess — including under load

A slowdown is usually not one cause but several at once. The first step is always an audit: TTFB measurement (separately for cold and warm cache — the first hit after a cache clear can be much slower), slow query log analysis, PHP profiling and a hosting test. Only the data shows what to fix first to get the biggest effect for the least effort. For tougher, cross-layer cases, an APM or transaction profiling (e.g. Blackfire, Tideways, New Relic, Datadog, OpenTelemetry) that ties a single request to the controller, module, SQL and external API helps.

A single test does not show how the store behaves under load — PrestaShop may respond in 300 ms for one request yet slow to several seconds during a campaign or a bot surge. Run a controlled load test — preferably against a production-like environment or in an agreed window, on safe endpoints and with a capped rate, because a test can overload the store, send emails, create carts, fire integrations and trip the WAF. For realistic scenarios use k6 or a similar tool that handles sequences, cookies and multiple endpoints (treat ab as only a simple single-URL test). Watch, at the same time, CPU, I/O wait, load average, the PHP-FPM queue, MySQL Threads_running, throughput (RPS) and the error rate (timeouts, 429, 5xx), and the p95/p99 response time, not just the average. And do not judge the store by a single Lighthouse run — compare lab data with real-user Core Web Vitals (CrUX) and with server-side measurements.

Frequently Asked Questions

How fast should a PrestaShop store load?

LCP below 2.5 s on mobile is the "good" Core Web Vitals threshold. For TTFB we aim at ~400 ms — a stricter in-house target than web.dev's rough ~800 ms guideline. Above those values the bounce rate rises, and poor Core Web Vitals can lower your Google ranking. The exact thresholds depend on the page type (home, category, product) and traffic.

Can you speed up PrestaShop without changing hosting?

Often yes — OPcache, correct Smarty compilation settings, query and front-end optimization (and, in justified cases, Redis or Memcached) can deliver a big gain on the same server. But if hosting is the bottleneck (high disk latency, CPU limits, insufficient memory), application-level optimization alone is not enough and a migration pays off.

Where should I start diagnosing a slow store?

With measurement, not guesswork: TTFB, slow query log, PrestaShop profiling and PageSpeed Insights. These four sources usually point to the 2–3 causes responsible for most of the slowdown.

Not sure what is slowing your store down?

Send your store URL and get a preliminary performance assessment — you will see what is worth checking first and what the likely scope of work is.