Skip to content

HTTP status code · Unofficial, used by nginx

499 Client Closed Request

499 Client Closed Request is an nginx log code meaning the client closed the connection before nginx sent a response. The usual cause is a backend slower than the client’s own timeout: a load balancer, CDN, mobile app or impatient user gave up first.

Facts about this status code
Class4xx/5xx, Unofficial codes (nginx, Cloudflare)
Defined innginx source: NGX_HTTP_CLIENT_CLOSED_REQUEST
Cacheable by defaultNo; the client is gone before anything is sent
Safe to retryThe client already gave up; a retry only helps if it waits longer or the backend gets faster
Relevant headersNone specific to this code

What 499 means

The code is defined in the nginx source as NGX_HTTP_CLIENT_CLOSED_REQUEST and is never sent to anyone: by the time nginx would write it, the socket is already closed. It exists so that your access log explains a request that otherwise would look like it vanished.

A 499 points at a timeout mismatch more often than at a bug. If Cloudflare in front of your origin stops waiting after its 125-second proxy read timeout, or an application load balancer has a 60-second idle timeout, nginx behind it logs 499 for every request that takes longer, while the visitor sees a 524 or 504 from that front proxy.

By default nginx also closes the connection to the upstream when the client leaves (proxy_ignore_client_abort off), so the backend may be interrupted mid-work. Turn that directive on only when the upstream work must finish regardless, such as a payment callback.

Common causes

If you are visiting the site

  • You closed the tab, pressed stop, or navigated away while the page was still loading.
  • A flaky mobile connection dropped mid-request, or the app you use has a short request timeout.

If you run the server

  • The upstream (PHP-FPM, Node, a database query) takes longer than the timeout of whatever sits in front of nginx: a CDN, a cloud load balancer or a client library default.
  • Health checks or monitoring probes with a timeout of a few seconds hitting a slow endpoint.
  • Users double-clicking or search-as-you-type code aborting the previous fetch with AbortController, which is harmless and shows up as short 499s.

How to fix it

If you are visiting the site

  • Reload and wait for the page to finish; if it hangs again, the slowness is on the server side.

If you run the server

  • Log $request_time and $upstream_response_time. 499s that cluster around one value (60 s, 100 s, 125 s) reveal the timeout of the component in front of nginx.
  • Make the slow endpoint faster, or move the long work to a background job and return 202 Accepted with a status URL to poll.
  • Order the timeouts from the inside out: backend shorter than nginx proxy_read_timeout, which is shorter than the load balancer or CDN, so failures surface as a clear 504 from nginx instead of a 499.
  • Ignore short 499s from cancelled fetches in alerts; they are expected client behavior.

How to diagnose 499

You never send 499 yourself; nginx writes it to the access log when the client disconnects. The snippets show how to log it usefully and find the pattern.

Nginx
# 499 lands in $status; log timings to see who gave up first
log_format timing '$remote_addr "$request" $status '
                  'rt=$request_time urt=$upstream_response_time';
access_log /var/log/nginx/access.log timing;

location /api/ {
    proxy_pass http://app;
    proxy_read_timeout 60s;
    # Optional: let the upstream finish even if the client leaves
    # proxy_ignore_client_abort on;
}
Shell
# Which URLs get the most 499s (default combined log: status is field 9)
awk '$9 == 499 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

# With the timing format above: how long did those requests run?
grep ' 499 rt=' /var/log/nginx/access.log | grep -o 'rt=[0-9.]*' | sort | uniq -c | sort -rn | head

Commonly confused with

499 vs 408
408 is the server giving up on a client that is too slow to send its request; 499 is the client giving up on a server that is too slow to answer.
499 vs 504
504 is nginx itself timing out on the upstream and telling the client; 499 means the client left before nginx reached its own timeout.
499 vs 444
444 is nginx closing the connection on purpose; 499 is the other side closing it.

Frequently asked questions

Is a 499 error a problem with my server?
Often, yes, indirectly. A few short 499s are normal cancellations, but many 499s with long request times mean the backend is slower than the timeout of the client or proxy in front of nginx.
Why do I see 499 in nginx but 524 or 504 in the browser?
Something between the browser and nginx timed out first. Cloudflare shows 524 after its 125-second read timeout; a load balancer shows 504. That proxy then closes its connection to nginx, which nginx logs as 499.
Does the backend keep running after a 499?
By default nginx closes the upstream connection too, but most application servers do not notice until they try to write, so the work usually runs to completion anyway. Design long operations to be idempotent or move them to a queue.
Should I turn on proxy_ignore_client_abort?
Only for endpoints whose work must finish even if the caller leaves. It keeps the upstream connection open after the client disconnects; it does not make the response reach anyone.

Last reviewed by Arielton Oberek.