What Is TTFB and Why Should You Care?
Time to First Byte (TTFB) measures the duration between a browser sending an HTTP request and receiving the very first byte of the response. It is the single most telling metric about your server's responsiveness. While total page load depends on many factors — asset sizes, JavaScript execution, rendering — TTFB tells you how fast your server thinks.
Google has been explicit: TTFB is a ranking signal within Core Web Vitals. A TTFB under 200ms is considered Good, between 200ms and 500ms is Needs Improvement, and anything above 500ms is Poor. Beyond SEO, every 100ms of added latency costs measurable conversion revenue — Amazon famously quantified this at 1% of sales per 100ms.
Measuring TTFB: Know Your Baseline
Before optimizing, you need accurate measurements. Here are three reliable methods to measure TTFB, each with different strengths.
Method 1: curl with Timing Breakdown
The most precise local measurement uses curl's built-in timing variables. This gives you a complete breakdown of every phase of the connection.
"DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
https://example.com
DNS: 0.024s
Connect: 0.048s
TLS: 0.112s
TTFB: 0.387s
Total: 0.412s
The time_starttransfer value is your TTFB. In this example, 387ms — well above our 200ms target. The breakdown reveals where time is being spent: DNS lookup took 24ms, TCP handshake added another 24ms, TLS negotiation consumed 64ms, and server processing took 275ms.
Method 2: Chrome DevTools
Open DevTools (F12), go to the Network tab, click on your document request, and look at the Timing section. The "Waiting for server response" value is your TTFB. This measures from a real browser, including any real-world network conditions.
Method 3: WebPageTest
For measuring TTFB from different geographic locations, WebPageTest is invaluable. Run tests from multiple regions to understand how TTFB varies for your global audience. The "First Byte" metric in the results corresponds to TTFB.
The Anatomy of TTFB: What Makes It Slow
TTFB is the sum of several sequential operations. Understanding each component is essential for targeted optimization.
10-100ms
10-50ms
30-100ms
50-2000ms+
TTFB!
DNS, TCP, and TLS are network-level costs you can reduce but not eliminate. Server processing time — the time your application actually spends generating the response — is where the biggest wins hide. Let us attack each layer systematically.
Layer 1: PHP-FPM Pool Optimization
For PHP-based sites (WordPress, Laravel, custom apps), PHP-FPM configuration is the single biggest lever for TTFB. A misconfigured pool causes worker starvation, where requests queue up waiting for an available PHP process.
Understanding Process Managers
| Manager | Behavior | Best For |
|---|---|---|
| static | Fixed number of workers, always running | Dedicated servers with predictable load |
| dynamic | Workers scale between min and max | Most web servers (recommended) |
| ondemand | Workers spawn only on request | Low-traffic sites, many pools |
Tuning the Dynamic Manager
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 500
pm.process_idle_timeout = 10s
The formula for pm.max_children is straightforward: take your available RAM, subtract what the OS and other services need, and divide by the average memory per PHP worker (typically 30-50MB). On a server with 4GB RAM and 1GB reserved for the system:
pm.max_requests = 500 to prevent memory leaks from accumulating over time.
Layer 2: OPcache — Eliminate PHP Compilation
Every time PHP processes a script, it parses the source code, compiles it to opcodes, and then executes those opcodes. OPcache stores compiled opcodes in shared memory, completely eliminating the parse and compile phases on subsequent requests. This alone can cut PHP execution time by 50-70%.
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.save_comments=1
opcache.jit=1255
opcache.jit_buffer_size=128M
validate_timestamps=0 means PHP never checks if source files have changed. This gives maximum performance but requires you to restart PHP-FPM after deploying new code. In development, keep validate_timestamps=1 with revalidate_freq=2.
The JIT (Just-In-Time) compiler in PHP 8.x provides additional gains for CPU-intensive operations. The 1255 configuration enables tracing JIT with optimizations. For most web applications, OPcache preloading combined with JIT can bring PHP execution time under 10ms for cached scripts.
Layer 3: Database Query Optimization
Slow database queries are the most common cause of high TTFB. A single unindexed query can add hundreds of milliseconds to every page load.
Identify Slow Queries
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0.1
# Analyze slow queries
$ mysqldumpslow -s t /var/log/mysql/slow.log
Count: 2847 Time=0.32s Lock=0.00s Rows=1.0
SELECT * FROM wp_options WHERE option_name = 'S'
Common Query Fixes
- Add composite indexes for WHERE + ORDER BY combinations
- Replace
SELECT *with specific columns you actually need - Use EXPLAIN to verify queries hit indexes, not full table scans
- Enable MySQL query cache or use application-level caching for repeated queries
- Optimize JOIN queries — ensure join columns are indexed on both tables
- Use connection pooling to eliminate per-request connection overhead
WordPress-Specific: The autoload Problem
WordPress loads every option with autoload=yes on every single page request. Over time, plugins add thousands of autoloaded options, ballooning this query. Check your autoload size:
FROM wp_options WHERE autoload = 'yes';
+---------------+
| autoload_size |
+---------------+
| 3847291 |
+---------------+
If this exceeds 1MB, you have a problem. Audit plugins and set unnecessary options to autoload=no.
Layer 4: Nginx FastCGI Cache (Full-Page Caching)
The most dramatic TTFB improvement comes from serving cached responses directly from Nginx, bypassing PHP entirely. A fastcgi_cache hit serves in 1-5ms versus 100-300ms for PHP processing.
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2 keys_zone=PHPCACHE:100m
inactive=60m max_size=1g use_temp_path=off;
# server block — Enable caching
set $skip_cache 0;
# Skip cache for logged-in users
if ($http_cookie ~* "wordpress_logged_in") {
set $skip_cache 1;
}
# Skip cache for POST requests
if ($request_method = POST) {
set $skip_cache 1;
}
location ~ \.php$ {
fastcgi_cache PHPCACHE;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-Cache-Status $upstream_cache_status;
}
The X-Cache-Status header lets you verify caching is working. You will see HIT for cached responses, MISS for first requests, and BYPASS for skipped requests (logged-in users, POST requests).
Layer 5: Object Caching
Object caching stores the results of expensive database queries and computations in memory. Instead of hitting the database for every request, your application checks the in-memory cache first. This is particularly impactful for dynamic pages that cannot use full-page caching.
Common object cache backends include Memcached and in-memory stores. For WordPress specifically, a custom-built caching system or a persistent object cache can reduce database queries from 200+ per page to under 10.
Layer 6: Reducing TLS Handshake Time
The TLS handshake can add 50-150ms to your TTFB. While you cannot eliminate it (HTTPS is non-negotiable), you can significantly reduce it.
OCSP Stapling
Without OCSP stapling, the browser makes a separate request to the Certificate Authority to verify your certificate's revocation status. This adds 100-300ms. OCSP stapling lets your server include the CA's response directly in the TLS handshake.
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
TLS Session Resumption
TLS session tickets and session IDs allow returning visitors to resume previous TLS sessions without a full handshake, cutting the TLS phase from two round trips to one.
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets on;
Layer 7: Connection Keep-Alive and HTTP/2
Keep-alive connections reuse existing TCP connections for multiple requests, eliminating the TCP+TLS handshake for subsequent requests. HTTP/2 takes this further with multiplexing — multiple requests over a single connection.
listen 443 ssl http2;
keepalive_timeout 65;
keepalive_requests 1000;
# Upstream keep-alive (to PHP-FPM)
upstream php-fpm {
server unix:/var/run/php-fpm.sock;
keepalive 16;
}
Layer 8: Early Hints (HTTP 103)
HTTP 103 Early Hints is a relatively new feature that lets the server send preliminary headers while the main response is still being generated. The browser can start loading CSS and fonts before the HTML even arrives.
location / {
add_header Link "</css/main.css>; rel=preload; as=style" early;
add_header Link "</fonts/inter.woff2>; rel=preload; as=font" early;
}
While Early Hints do not reduce actual TTFB, they reduce the perceived load time by allowing parallel resource fetching during server processing. This can shave 100-200ms off total page load.
Layer 9: CDN for TTFB Reduction
A CDN places edge servers geographically close to your visitors. For static assets, this reduces TTFB dramatically. For dynamic content, many CDNs offer edge caching with cache-control headers or even edge computing (Cloudflare Workers, AWS Lambda@Edge).
| Scenario | Origin Only | With CDN | Improvement |
|---|---|---|---|
| User in same country as server | 80ms | 20ms | -75% |
| User on different continent | 350ms | 40ms | -89% |
| Dynamic page (cached at edge) | 250ms | 15ms | -94% |
| Dynamic page (not cacheable) | 250ms | 180ms | -28% |
Even for non-cacheable dynamic content, CDNs reduce TTFB through optimized routing (Anycast), persistent connections to origin, and protocol optimizations (HTTP/2 to origin, TCP window tuning).
Real-World Optimization: A Case Study
Here is a real optimization sequence on a WordPress site running on a 4-core, 8GB RAM server. Each step was measured independently to show its individual impact.
| Step | Change | TTFB | Delta |
|---|---|---|---|
| Baseline | Default PHP-FPM, no caching | 892ms | — |
| 1 | PHP-FPM dynamic pool tuning | 743ms | -149ms |
| 2 | OPcache enabled + JIT | 412ms | -331ms |
| 3 | Database index optimization | 318ms | -94ms |
| 4 | Object caching enabled | 247ms | -71ms |
| 5 | Nginx fastcgi_cache | 8ms | -239ms |
| 6 | TLS session resumption + OCSP | 6ms | -2ms |
| Final | All optimizations combined | 6ms | -886ms |
The Complete TTFB Optimization Checklist
Apply these optimizations in order of impact. Each builds on the previous one.
memory_consumption=256, validate_timestamps=0 for production, and enable JIT on PHP 8.x.Monitoring TTFB in Production
Optimization is not a one-time task. You need continuous monitoring to catch regressions. Set up automated TTFB checks using synthetic monitoring or real user monitoring (RUM).
*/5 * * * * curl -o /dev/null -s -w "%{time_starttransfer}" \
https://example.com >> /var/log/ttfb.log 2>&1
# Alert if TTFB exceeds 200ms
TTFB=$(curl -o /dev/null -s -w "%{time_starttransfer}" https://example.com)
if (( $(echo "$TTFB > 0.200" | bc -l) )); then
echo "TTFB alert: ${TTFB}s" | mail -s "High TTFB" [email protected]
fi
How Panelica Optimizes TTFB
Panelica optimizes TTFB out of the box with its architecture decisions. Per-user PHP-FPM pools run with OPcache pre-configured for production workloads, eliminating the most common cause of high TTFB. The Nginx configuration ships with fastcgi caching support and HTTP/2 with TLS session resumption enabled by default.
The isolation architecture means one user's slow PHP scripts never impact another user's TTFB — each user's PHP-FPM pool runs independently with its own resource limits. Combined with database optimization tools and built-in Cloudflare integration for CDN, most sites serve under 200ms TTFB on a properly configured Panelica server without any manual tuning.