Key Takeaways
- Page caching is table stakes; object caching (Redis/Memcached) is where real gains happen
- PHP 8.2+ with OPcache properly configured provides 20-30% free performance
- Database optimization—proper indexing, query optimization, cleanup—often yields the biggest improvements
- Server-level decisions (PHP-FPM tuning, MySQL configuration) matter more than most plugins
- CDN + edge caching moves processing closer to users; essential for global audiences
Beyond the Basics
You've compressed your images. You've installed a caching plugin. Your PageSpeed score improved from 30 to 60. Now what?
The basic WordPress optimization advice is well-documented: optimize images, enable caching, reduce plugins. But for sites that need to handle serious traffic or provide sub-second response times, the basics aren't enough.
This guide covers the deeper optimizations—the server configuration, database tuning, and architectural decisions that separate adequate performance from exceptional performance. These are techniques I use on enterprise WordPress installations handling millions of pageviews.
We'd done all the standard optimizations and hit a wall at 200ms response time. Server-level tuning got us to 50ms. That's the difference users actually feel.
DevOps Engineer, Media Company
Fair warning: some of these optimizations require server access and technical comfort. If you're on shared hosting, you'll hit limits quickly. Consider this a roadmap for when you're ready to level up.
The Performance Stack
Understanding where time is spent helps prioritize optimizations. A typical WordPress request flows through these layers:
-
DNS Resolution
Converting your domain name to an IP address. Usually 20-120ms. Optimize with a fast DNS provider (Cloudflare, Route 53) and appropriate TTLs.
-
TLS Handshake
Establishing the secure connection. 50-150ms for new connections. Optimize with TLS 1.3, session resumption, and HTTP/2 or HTTP/3.
-
Server Processing
PHP executing WordPress code, querying the database, assembling the response. 100-2000ms+ depending on optimization. This is where most gains are found.
-
Network Transfer
Sending the response to the user. Depends on response size and connection speed. Optimize with compression, minification, and CDN.
-
Browser Rendering
Parsing HTML, loading assets, executing JavaScript. 100-500ms+. Optimize with critical CSS, deferred JS, and efficient asset loading.
The Biggest Lever
Server processing time is typically 60-80% of total response time for uncached requests. Reducing a 500ms server response to 100ms has more impact than any frontend optimization.
PHP Configuration
PHP is where WordPress lives. Proper PHP configuration is foundational to performance.
Use the Latest PHP Version
PHP 8.x is significantly faster than PHP 7.x, which was significantly faster than PHP 5.x. Each major version brings substantial performance improvements—often 20-30% faster execution.
Current recommendation: PHP 8.2 or 8.3. Check WordPress and plugin compatibility, but don't stay on old versions without reason.
OPcache Configuration
OPcache stores precompiled PHP scripts in memory, eliminating the need to parse and compile on every request. It's enabled by default in modern PHP but often not optimally configured.
; Recommended OPcache settings for WordPress
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=0
opcache.validate_timestamps=0 ; Disable in production
opcache.save_comments=1
opcache.enable_file_override=1
validate_timestamps=0
PHP-FPM Pool Configuration
PHP-FPM manages PHP worker processes. Proper configuration prevents bottlenecks under load.
; PHP-FPM pool settings
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
; Memory limit per process
php_admin_value[memory_limit] = 256M
The right values depend on your server's RAM and traffic patterns. The formula: max_children = (Total RAM - System RAM) / Average PHP Process Size. Monitor with tools like pm.status_path to tune based on actual usage.
Database Optimization
WordPress is database-heavy. A typical page load might execute 50-200 database queries. Database optimization often yields the biggest performance gains.
MySQL/MariaDB Configuration
Default MySQL settings are conservative. Tuning for WordPress workloads makes a significant difference.
# Key MySQL settings for WordPress
innodb_buffer_pool_size = 1G # 70-80% of available RAM for dedicated DB server
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2 # Slight durability tradeoff for performance
innodb_flush_method = O_DIRECT
query_cache_type = 0 # Disabled in MySQL 8.0+, use object caching instead
max_connections = 150
tmp_table_size = 64M
max_heap_table_size = 64M
Query Optimization
Slow queries are often the biggest performance killer. Identify them with the slow query log:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
Common culprits in WordPress:
- Unindexed meta queries:
WP_Querywith multiplemeta_queryparameters - Autoload bloat: Plugins storing large data with
autoload=yes - Post type archives: Queries across thousands of posts without proper limits
- Taxonomy queries: Complex term relationships without proper indexing
Database Maintenance
Regular maintenance keeps the database lean:
- Delete post revisions beyond what you need (keep 3-5)
- Remove orphaned postmeta and termmeta
- Clean up transients (especially expired ones)
- Optimize tables periodically (
OPTIMIZE TABLE) - Archive or delete old data (logs, analytics, etc.)
The Autoload Problem
Object Caching
Page caching serves static HTML to anonymous users. But what about logged-in users, dynamic content, and admin operations? That's where object caching shines.
What Object Caching Does
Object caching stores the results of expensive operations (usually database queries) in memory. When WordPress or a plugin asks for data, it checks the cache first. Cache hit = instant response. Cache miss = query database, store result for next time.
WordPress has built-in object caching, but by default it only persists for a single request. Adding a persistent object cache (Redis or Memcached) makes cached data available across requests.
Redis vs. Memcached
| Feature | Redis | Memcached |
|---|---|---|
| Persistence | Yes (optional) | No |
| Data types | Strings, lists, sets, hashes, etc. | Strings only |
| Replication | Built-in | External tools needed |
| Memory efficiency | Good | Excellent |
| WordPress support | Excellent | Good |
| Recommendation | Preferred for WordPress | Fine for simple caching |
Implementation
- Install Redis on your server:
apt install redis-server - Install the Redis PHP extension:
apt install php-redis - Install a WordPress object cache drop-in (Redis Object Cache plugin or similar)
- Configure Redis connection in
wp-config.php - Verify with
redis-cli monitorwhile loading pages
// wp-config.php Redis configuration
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_TIMEOUT', 1 );
define( 'WP_REDIS_READ_TIMEOUT', 1 );
Cache Invalidation
The hardest problem in computer science. When content changes, stale cache must be cleared. WordPress handles this reasonably well for core functionality, but plugins vary. Monitor cache hit rates and stale content issues.
Full-Page Caching
For anonymous users viewing the same content, why generate the page repeatedly? Full-page caching stores the complete HTML response.
Caching Layers
Page caching can happen at multiple levels:
Application Level
WordPress caching plugins (WP Rocket, W3 Total Cache, WP Super Cache). Easy to configure, WordPress-aware, but PHP still loads.
Server Level
Nginx FastCGI cache or Varnish. Serves cached pages without touching PHP. Much faster but requires server configuration.
Edge Level
CDN edge caching (Cloudflare, Fastly, CloudFront). Cached at points of presence worldwide. Lowest latency for global audiences.
Browser Level
HTTP cache headers tell browsers to reuse responses. Reduces server requests entirely for returning visitors.
Nginx FastCGI Cache Example
# nginx.conf - FastCGI cache configuration
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
# Skip cache for logged-in users, POST requests, etc.
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php") { set $skip_cache 1; }
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") { set $skip_cache 1; }
location ~ \.php$ {
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-FastCGI-Cache $upstream_cache_status;
# ... other fastcgi settings
}
}
CDN and Edge Optimization
A Content Delivery Network caches your content at servers distributed globally. Users get content from the nearest location, dramatically reducing latency for geographically distributed audiences.
What to Cache at the Edge
- Static assets: Images, CSS, JS, fonts. Easy, no invalidation complexity.
- HTML pages: For anonymous users. Requires cache invalidation strategy.
- API responses: If they're cacheable. Consider cache headers carefully.
Cache Invalidation Strategies
- Time-based (TTL): Content expires after set duration. Simple but may serve stale content.
- Purge on publish: Clear specific URLs when content changes. Requires integration.
- Surrogate keys/tags: Tag cached content, purge by tag. Most flexible but complex.
- Stale-while-revalidate: Serve stale content while fetching fresh in background. Best user experience.
Cloudflare APO
Monitoring and Profiling
You can't optimize what you don't measure. Establish baselines and monitor continuously.
Key Metrics to Track
- Time to First Byte (TTFB): Server processing time. Should be under 200ms.
- Largest Contentful Paint (LCP): When main content is visible. Under 2.5s.
- Cache hit rates: Page cache, object cache, CDN. Aim for 90%+.
- Database query time: Total query time per request. Watch for regressions.
- PHP memory usage: Per-request memory. Indicates code efficiency.
- Error rates: 500 errors, timeouts, failed requests.
Profiling Tools
- Query Monitor: WordPress plugin showing queries, hooks, HTTP requests per page.
- New Relic / Datadog: APM tools for production profiling and alerting.
- Blackfire: PHP profiling showing exactly where time is spent.
- XHProf/Tideways: Open-source PHP profilers.
- MySQL slow query log: Identifies problematic database queries.
Profile Before Optimizing
Assumptions about bottlenecks are often wrong. Profile first, identify actual hot spots, then optimize. I've seen teams spend weeks optimizing things that accounted for 2% of response time.
Architecture Decisions
At some point, single-server optimization hits limits. Architectural decisions enable the next level of scale.
Separate Database Server
Moving MySQL to a dedicated server lets each optimize for its workload. The web server can dedicate all RAM to PHP; the database server can maximize buffer pool size.
Load Balancing
Multiple web servers behind a load balancer. Considerations:
- Session handling (sticky sessions or external session storage)
- File uploads (shared storage or object storage)
- Cache invalidation across servers
- Deployment coordination
Object Storage for Media
Moving media to S3, Google Cloud Storage, or similar offloads file serving from WordPress and enables CDN delivery. Plugins like WP Offload Media handle this.
Headless/Decoupled Architecture
For maximum frontend performance, serve WordPress as a headless CMS with a static or JavaScript frontend. This adds significant complexity but enables sub-100ms page loads.
Performance Checklist
A prioritized checklist for WordPress performance optimization:
Foundation (Do First)
- ☐ PHP 8.2+ with OPcache properly configured
- ☐ Quality hosting with adequate resources
- ☐ Page caching enabled and working
- ☐ Images optimized and served in modern formats
- ☐ CDN for static assets
Intermediate (High Impact)
- ☐ Redis/Memcached object caching
- ☐ Database optimization and cleanup
- ☐ Plugin audit (remove unnecessary plugins)
- ☐ Server-level page caching (Nginx FastCGI or Varnish)
- ☐ HTTP/2 or HTTP/3 enabled
Advanced (For Scale)
- ☐ Edge caching for HTML
- ☐ Database query optimization and indexing
- ☐ PHP-FPM pool tuning
- ☐ MySQL/MariaDB configuration tuning
- ☐ APM monitoring and alerting
Frequently Asked Questions
What is object caching in WordPress?
How much RAM does WordPress need for optimal performance?
Should I use Redis or Memcached for WordPress?
What PHP version is fastest for WordPress?
Need help optimizing your WordPress performance?
I help businesses identify bottlenecks and implement the optimizations that matter for their specific situation.