Time to First Byte (TTFB) is often the most frustrating metric to optimize. When you’re reducing TTFB for WordPress on Nginx, you’re essentially fighting the time it takes for your server to process a PHP request and send the first byte of data back to the browser. In my experience, a high TTFB is rarely about the network and almost always about how Nginx and PHP-FPM are communicating.
I’ve spent years tweaking WordPress stacks, and I’ve found that while plugins help, the real wins happen at the server level. If your server is taking 800ms just to ‘think’ before sending data, no amount of image optimization will save your Core Web Vitals.
Prerequisites
- A Linux server (Ubuntu/Debian preferred) running Nginx.
- WordPress installed and running via PHP-FPM.
- Root or sudo access to the server via SSH.
- Basic familiarity with editing configuration files using Nano or Vim.
Step 1: Implement Nginx FastCGI Caching
The single most effective way of reducing TTFB for WordPress on Nginx is to stop WordPress from having to generate the page every single time. FastCGI caching stores the HTML output of a page and serves it directly from Nginx, bypassing PHP and MySQL entirely for cached requests.
First, define the cache path in your nginx.conf file (usually in /etc/nginx/nginx.conf) inside the http block:
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100M inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
Next, apply the cache to your server block. As shown in the technical breakdown below, you need to tell Nginx when to cache and when to bypass (like when a user is logged in or posting a comment):
set $skip_cache 0;
# POST requests and URLs with a query string should always go to PHP
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
# Don't cache URIs containing the following segments
if ($request_uri ~* "/wp-admin/|/wp-login.php|/cart/|/checkout/") { set $skip_cache 1; }
# Don't cache users logged in
if ($http_cookie ~* "comment_author|wordpress_logged_in|wp-postpass") { set $skip_cache 1; }
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
}
Step 2: Tuning PHP-FPM and OPcache
When the cache is bypassed (for logged-in users), your TTFB depends entirely on PHP performance. I always ensure OPcache is enabled and tuned. OPcache stores precompiled script bytecode in shared memory, so PHP doesn’t have to load and parse scripts on every request.
Edit your php.ini file and ensure these settings are active:
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
I also recommend switching the PHP-FPM process manager to static if you have a dedicated server. This removes the overhead of spawning new child processes, which can shave off a few precious milliseconds of TTFB.
Step 3: Optimize MySQL Queries
Often, the bottleneck causing high TTFB is a slow database query. I use a plugin like Query Monitor to find slow queries, but from a server perspective, ensuring your innodb_buffer_pool_size is large enough to hold your indexes in memory is key.
If you are running a small site, you might wonder should I use a CDN for small websites to mask this? While a CDN helps with static assets, it doesn’t fix the TTFB of the initial HTML document unless you use “Edge Caching.” For a true fix, you must optimize the origin server.
Pro Tips for Extreme Performance
- Use HTTP/2 or HTTP/3: Ensure your Nginx config uses
listen 443 ssl http2;. This allows multiplexing, reducing the perceived delay in loading. - Disable Unused Plugins: Every active plugin adds to the PHP execution time. I regularly audit my site to remove anything not strictly necessary.
- Object Caching: Install Redis or Memcached. While FastCGI caches the whole page, Object Cache stores individual database results, reducing the load on MySQL for non-cached pages.
- Consider a CDN: If your users are global, the physical distance to your server adds to TTFB. Depending on your budget, you might look at Cloudflare vs Akamai for small business options to cache your HTML at the edge.
Troubleshooting
“My site is showing old content!”
This happens because FastCGI caching is too aggressive. Ensure your fastcgi_cache_valid is set to a reasonable time (e.g., 60m) and that you have a mechanism to purge the cache when updating posts.
“Nginx is returning a 502 Bad Gateway”
This usually means PHP-FPM crashed or the socket path in your Nginx config is wrong. Check your PHP version: ls /var/run/php/ and ensure the socket matches your fastcgi_pass directive.
What’s Next?
Once you’ve mastered reducing TTFB for WordPress on Nginx, the next step is optimizing the Critical Rendering Path. This involves minimizing CSS and delaying non-essential JavaScript so the page doesn’t just start loading fast, but actually becomes usable quickly.