Common causes
- A plugin calls session_start() and holds the PHP session lock, blocking the loopback request
- The server cannot resolve or reach its own domain (DNS, hosts file or firewall)
- A CDN, WAF or security plugin blocks or challenges requests from the server's own IP
- Too few PHP-FPM workers, so the loopback request waits behind the current one
- Slow plugins making every request exceed the timeout
- HTTP Basic Auth on a staging site rejecting the loopback request
How to fix it
- Test from the server itself. Over SSH run curl -I https://example.com/wp-json/ from the server. If it hangs, the problem is networking or the web server; if it is fast, look at WordPress itself.
- Look for session_start(). Site Health often adds 'A PHP session was created by a session_start() function call'. Find the plugin responsible and update or replace it; sessions should be closed with session_write_close() before requests.
- Check DNS and hosts file. Make sure the domain resolves to this server from the server (getent hosts example.com). Behind a CDN, adding a hosts entry pointing the domain to 127.0.0.1 or the server IP often helps.
- Whitelist the server's IP. Allow the server's own IP in Cloudflare WAF, Wordfence or other firewalls so loopback requests are not challenged.
- Increase PHP-FPM workers. On a VPS, raise pm.max_children so a loopback request does not wait for the request that triggered it. Shared-host users should ask support about process limits.
- Disable plugins to find slow code. Use Health Check & Troubleshooting's troubleshooting mode or rename plugins one at a time and re-run Site Health.
SSH diagnostics
getent hosts example.com
curl -sS -o /dev/null -w '%{http_code} %{time_total}s\n' \
https://example.com/wp-json/
wp cron test
wp cron event list --due-now How to stop it happening again
- Avoid plugins that open PHP sessions on every request
- Exclude the server's own IP from rate limiting and bot challenges
- Use a real system cron for wp-cron.php on busy sites