HTTP 499 Client Closed Request: who gave up, and why
499 is not a reply a server sends. nginx, and services built on it, write 499 in their logs when the client closes the connection before the response is ready. If it is in your logs, a caller stopped waiting: its timeout is shorter than your response time, or something between you and it closed the connection. The fix is to make the response faster or to line up the timeouts along the route.
Reviewed by John Hale. Last updated .
What it looks like
203.0.113.7 - - [14/Nov/2026:10:12:03 +0000] "GET /report HTTP/1.1" 499 0 "-" "curl/8.7.1"curl: (28) Operation timed out after 2006 milliseconds with 0 bytes receivedTimeoutError: The operation was aborted due to timeoutWhat does 499 Client Closed Request mean?
499 is not part of HTTP. RFC 9110 does not define it, and the IANA registry lists 452 to 499 as unassigned. nginx defines it in its source as NGX_HTTP_CLIENT_CLOSED_REQUEST, for a client that closes the connection while nginx is still working on the request. Nothing is sent, because the connection is gone: 499 exists only in the log.
Other services use it the same way. Cloudflare records 499 in its logs and analytics when a client closes the connection before the request is complete, and sends no 499 response. AWS Application Load Balancers log the same event as 460. Google APIs are the exception that puts it in a reply: a cancelled call maps to HTTP 499.
The client is whatever opened the connection to that server, not always a person. Behind a load balancer or a CDN it is the load balancer or the CDN. When a request comes through a proxy, it is the proxy's exit address.
What causes a 499?
Most likely first.
- The caller's timeout is shorter than the response time. The most common cause. A script with
--max-time 10, atimeout=10in Python or anAbortSignal.timeout()in JavaScript closes the connection when the time is up, and the server logs 499 for a request it was still working on. - A load balancer or CDN in front gave up first. When the layer in front of nginx has a shorter timeout than the application, it closes its connection to nginx and answers the visitor itself, usually with 504. nginx logs 499 and the visitor never sees that number.
- A person left. Closing the tab, pressing stop, clicking a link before the page finished or submitting a form twice all cancel requests that were in flight.
- The client cancels on purpose. Search boxes that cancel the previous request on each keystroke, clients that send the same request to two servers and drop the slower one, and health checks with a short deadline.
- A proxy or its exit dropped in the middle. When a request travels through a proxy, the server sees the proxy's exit as the client. If the exit goes offline or the proxy closes the tunnel, the server logs 499 although the program that sent the request was still waiting.
How do you find who closed the connection?
Log how long each request ran
$request_timeis the time from the first bytes read from the client to the log write.$upstream_response_timeis the time spent receiving the answer from the application. 499s whose request time piles up at a round number such as 10.000, 30.000 or 60.000 point to a timeout set by the caller or by a layer in front.nginx.conflog_format timed '$remote_addr [$time_local] "$request" $status $body_bytes_sent ' 'rt=$request_time urt=$upstream_response_time "$http_user_agent"'; access_log /var/log/nginx/access.log timed;See which URLs are abandoned
In the default combined log format the status is the ninth field and the path the seventh. A few slow URLs with most of the 499s are a speed problem; 499s spread evenly over every URL point to the network or to a layer in front.
Most abandoned pathsawk '$9 == 499 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | headCheck who the client is
Look at the address in the log line. If it is your load balancer or your CDN, the visitor did not close the connection: that layer did, and its own log has the status the visitor received.
Reproduce it with a deadline
Give curl less time than the URL needs. curl prints error 28 and status 000, and the server logs 499 for that request.
Two seconds for a slow URLcurl -sS -o /dev/null --max-time 2 -w "%{http_code} %{time_total}s\n" https://TARGET/slow
How do you fix 499s?
Answer faster, or answer early
Speed up the slow URLs the log points to. For work that takes long by nature, accept the request, answer at once with a job ID and let the caller ask for the result.
Line up the timeouts
Each layer should wait a little longer than the one behind it: the application's own limit shortest, then nginx's
proxy_read_timeout, then the load balancer or CDN, and the caller longest. Then a slow request ends as a clear 504 from your side, not as a closed connection.Let important work finish
By default nginx closes its connection to the application when the client leaves.
proxy_ignore_client_abort onkeeps it open until the application answers. Use it for requests that must not be cut short, such as payments.nginx.conflocation /payments/ { proxy_ignore_client_abort on; proxy_pass http://app; }Make repeats safe
The application may finish the work after the caller has gone. In our test a server that took 10 seconds completed and wrote its answer without any error, 8 seconds after the caller had closed the connection. Before a client retries a request that changes something, give the request an idempotency key so the second attempt does not do the work twice.
On the calling side
Set a timeout that fits the slowest answer you expect, and retry requests that are safe to repeat with a growing pause. Through a proxy, allow for the longer route: a deadline that works on a direct connection can be too short through a residential exit.
If you use TrueProxies
The gateway never answers 499. When it refuses a connection itself, it answers 407, 403, 502 or 503, with the reason in X-Proxy-Reason where there is one.
When your client gives up, the tunnel closes and the website sees the proxy exit close its connection. A site that runs nginx logs that as 499 against the exit address. Traffic that moved before the close still counts as traffic used.
Usage history on the service page lists these connections under Ended on your side: Reset on your side, Timed out on your side and Left open after response. They are not proxy errors and do not count against connection success.
A residential exit can go offline in the middle of a connection. A sticky session then gets a new IP; keep the session ID and retry.
Test the proxy from outside your network
The free proxy checker connects from our servers and reports the failed stage as a code, so you can tell a proxy problem from one on your computer or network.
Questions about 499 Client Closed Request
Is a 499 an error on my server?
Not by itself. It says the caller left before the answer was ready. It becomes your problem when the answer was slow enough to make callers leave, so look at the request times of the 499s.
What is the difference between 499 and 504?
With a 504 a gateway waited for the server behind it, gave up and told the client. With a 499 the client left first, so there was nobody to tell. The same slow request can be a 499 in the nginx log and a 504 from the load balancer in front of it.
What is the difference between 499 and 408?
A 408 Request Timeout is sent by a server that gave up waiting for the client to finish sending its request. A 499 is logged when the client gave up waiting for the response.
Can a client ever receive a 499?
Not from nginx or Cloudflare, which only log it. Some APIs do send it: Google APIs answer a cancelled call with HTTP 499.
Does the server stop working when the client leaves?
nginx closes its connection to the application unless proxy_ignore_client_abort is on. Whether the application stops depends on the application: many keep working until they try to write the answer, and some never notice.
Why do 499s rise when I scrape through proxies?
The route is longer, so answers take longer, and a deadline tuned for a direct connection starts to cut requests off. Each one shows as a timeout in your scraper and as a 499 in the site's log. Raise the deadline or run fewer requests at once.
Sources
- NGX_HTTP_CLIENT_CLOSED_REQUEST in ngx_http_request.h — nginx
- proxy_ignore_client_abort and proxy_read_timeout — nginx
- Log format and $request_time — nginx
- Error 499 — Cloudflare
- Troubleshoot your Application Load Balancers: HTTP 460 — AWS
- google.rpc.Code: CANCELLED maps to HTTP 499 — Google
- HTTP status code registry — IANA
- 408 Request Timeout and 504 Gateway Timeout (RFC 9110) — IETF / RFC Editor
Related errors
502 Bad Gateway from a proxy
The proxy, or the site's own gateway, got no usable answer from the server behind it.
ECONNRESET through a proxy
Connection reset by peer in Node.js or Python: stale keep-alive sockets, the wrong port, or a cut route.
curl error 56
Recv failure, Proxy CONNECT aborted or CONNECT tunnel failed: what each curl (56) message means.
The proxy checker error codes page maps each checker code to the stage that failed, and proxy errors explained covers timeouts and slow connections.