Slow WordPress sites lose visitors. According to Google, 53% of mobile users abandon a site that takes longer than 3 seconds to load. For every second delay, conversion rates drop by an average of 2.5%.
After optimising over 500 WordPress sites on our managed hosting platform, we've developed a performance stack that consistently delivers sub-200ms Time to First Byte (TTFB) and Lighthouse scores above 95 โ even for complex WooCommerce and membership sites.
This guide walks through every layer of our optimisation stack, from the web server to the database. Apply these techniques to your own WordPress site, or let Hostingowy's managed WordPress hosting handle it for you automatically.
After: 189ms TTFB, 97 Lighthouse score, 34% bounce rate
Improvement: 91% faster load times โ results from a typical WooCommerce site migrated to our stack.
The Stack That Works
After benchmarking dozens of configurations, here's our proven stack:
- Nginx (not Apache) โ event-driven, handles 10x more concurrent connections with less memory
- PHP 8.2 FPM with OPcache โ JIT compilation, preloading, and opcode caching
- Redis for full-page caching and object cache โ in-memory, sub-millisecond reads
- Cloudflare CDN โ global edge caching, DDoS protection, HTTP/3 support
- MariaDB 10.11 with query cache and InnoDB tuning
- Brotli compression โ 20% better compression ratio than gzip
Layer 1: Web Server โ Nginx Configuration
Swap Apache for Nginx for an immediate 40-60% improvement in concurrent connection handling. Here's our production Nginx configuration for WordPress:
# /etc/nginx/sites-available/wordpress
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
root /var/www/example.com/public;
index index.php;
# SSL (use Let's Encrypt with certbot)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Static file caching
location ~* \.(css|js|gif|ico|jpe?g|png|svg|webp|woff2?)$ {
expires 365d;
add_header Cache-Control "public, immutable";
access_log off;
}
# Redis full-page cache check
set $cache_key $scheme://$host$request_uri;
set $skip_cache 0;
# Skip cache for logged-in users and commenters
if ($http_cookie ~* "comment_author|wordpress_logged_in|wp-postpass") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# FastCGI caching
fastcgi_cache WORDPRESS;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache_valid 200 301 302 60m;
fastcgi_cache_use_stale error timeout updating;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
Layer 2: PHP 8.2 FPM & OPcache Tuning
PHP 8.2 introduced significant performance improvements over previous versions, including JIT compilation and inherited cache for OPcache. Here's our tuned configuration:
; /etc/php/8.2/fpm/php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.jit=tracing
opcache.jit_buffer_size=100M
opcache.jit_hot_func=10
opcache.jit_hot_loop=5
; FPM pool settings
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 500
Layer 3: Redis Full-Page Caching
Redis keeps fully rendered HTML pages in memory, serving them in under 5ms without touching PHP or MySQL. We configure Redis with:
- Maxmemory policy: allkeys-lru (evict least recently used)
- Persistence: RDB snapshots every 5 minutes
- Memory allocation: 512MB-2GB depending on site size
- Connection: Unix socket for lower latency (vs TCP)
Use the Redis Object Cache plugin for fine-grained control, or implement full-page caching directly in Nginx (as shown above) for maximum performance.
Layer 4: Database Optimisation
MariaDB/MySQL is often the bottleneck. Here's our tuning checklist:
# /etc/mysql/mariadb.conf.d/99-wordpress.cnf
[mysqld]
innodb_buffer_pool_size = 2G # 70-80% of available RAM
innodb_log_file_size = 512M # Reduce checkpoint frequency
innodb_flush_log_at_trx_commit = 2 # Better performance (slightly less durable)
innodb_file_per_table = 1
query_cache_type = 1
query_cache_size = 128M
query_cache_limit = 2M
# Slow query log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# Connection pooling
max_connections = 200
thread_cache_size = 8
Additional Database Optimisations
- Index your meta queries: WooCommerce and Advanced Custom Fields can create thousands of postmeta rows. Index meta_key and meta_value.
- Clean up transients: Expired transients bloat the options table. Run
wp transient delete --expiredweekly. - Optimise tables:
wp db optimizemonthly to reclaim space. - Use persistent connections: Avoids the overhead of creating new MySQL connections for each request.
Layer 5: CDN & Edge Caching
Cloudflare's CDN serves static assets from 330+ data centres globally. Key configuration:
- Cache Everything page rule for HTML with edge TTL of 1 hour
- Brotli compression enabled (20% smaller than gzip)
- HTTP/3 (QUIC) for faster connection establishment
- Early Hints (103 Early Hints) for preloading critical CSS/JS
- Rocket Loader for deferred JavaScript loading
Layer 6: Asset Optimisation
Frontend assets are often the heaviest part of a WordPress page:
| Technique | Impact | Implementation |
|---|---|---|
| WebP/AVIF conversion | 25-35% smaller images | EWWW Image Optimizer or ShortPixel |
| Critical CSS inline | Eliminates render-blocking CSS | Autoptimize or WP Rocket |
| Deferred JS | Improves LCP by 15-25% | Add defer attribute to non-critical scripts |
| Font subsetting | 50-70% smaller font files | Google Fonts subset parameter or self-host subset |
| Lazy loading | Reduces initial page weight by 40-60% | Native loading="lazy" attribute |
Benchmark Results
We tested this stack against 50 WordPress sites. Here are the average improvements:
| Metric | Before (Basic LAMP) | After (Hostingowy Stack) | Improvement |
|---|---|---|---|
| TTFB (Time to First Byte) | 1,842ms | 189ms | 89.7% |
| Largest Contentful Paint (LCP) | 4.2s | 0.9s | 78.6% |
| First Input Delay (FID) | 85ms | 12ms | 85.9% |
| Cumulative Layout Shift (CLS) | 0.32 | 0.04 | 87.5% |
| Lighthouse Performance Score | 47 | 97 | +50 points |
| Requests per second (Nginx) | 450 | 3,200 | 7.1x |
Automated Optimisation with Hostingowy
Our Managed WordPress Hosting platform applies all of these optimisations automatically:
- Nginx + PHP 8.2 FPM + Redis pre-configured and tuned
- Automatic Cloudflare CDN integration
- Weekly database optimisation and transient cleanup
- Automatic image optimisation (WebP conversion)
- Built-in staging environment for testing changes
- 24/7 performance monitoring with automated alerting
No configuration required. Just point your domain and we handle the rest with 99.9% uptime SLA and UK-based support.
Conclusion
WordPress performance tuning is a multi-layer challenge. By optimising at every level โ web server, PHP runtime, caching, database, CDN, and assets โ you can achieve sub-200ms load times that delight visitors and improve conversion rates.
If you don't want to manage this yourself, Hostingowy's Managed WordPress plans include all of these optimisations out of the box, starting at just ยฃ8/month.