Error reference HTTP status

499 Client Closed Request: when the client hangs up first

HTTP 499 appears in nginx access logs when a client disconnects before the server finishes responding. It is not sent over the wire — it records an abort. The usual cause is a timing mismatch: the client's deadline is shorter than the server's response time. Fixing it means tuning timeouts, speeding up the slow path, or both.

499 Client Closed Request

What 499 Client Closed Request means

499 is a non-standard code that nginx writes to its access log when the client closes the connection before nginx has delivered a response. It is purely a bookkeeping entry — nothing with a 499 status line is ever sent, because there is no longer anyone to send it to. The client, meanwhile, records its own version of events: a timeout exception, a cancelled request, or a closed socket.

Every 499 is a timing mismatch: the client's patience ran out before the server's answer arrived. The usual suspects are HTTP client timeouts set shorter than real response times, load balancers or health checks with tight deadlines sitting in front of slow endpoints, users navigating away from a slow page, and retry logic that cancels an in-flight request to issue a new one.

Sustained 499 storms usually indicate backend latency, and they are self-reinforcing: clients that time out often retry, which adds load to an already slow backend, which pushes more requests past the deadline. Fixing the slow path matters as much as tuning the timeout.

499 Client Closed Request

How to fix 499 errors

Whether you own the server logging 499s or you are the client causing them, the fix is the same alignment problem: every deadline in the chain must be longer than the work behind it. Check these in order.

  1. Measure the real response time of the affected endpoints (nginx logs it as request_time) and compare it against the client's timeout. A 499 means the deadline was shorter than the latency — confirm by how much.
  2. Raise the timeout where you control the client: timeout= in Python requests, --max-time in curl, the idle timeout on your load balancer, or the deadline in your job runner.
  3. Fix the slow backend path: profile the endpoints that appear in 499 log lines for slow queries, missing indexes, cold caches, and blocking external calls.
  4. Align the timeout chain so each layer closer to the user waits at least as long as the layers behind it — otherwise a slow-but-successful response is thrown away as an abort.
  5. Audit retry logic. Clients that cancel and immediately re-issue requests convert one slow request into several, multiplying load; add exponential backoff and an overall retry budget.
  6. Look for health checks and monitoring probes with one-to-two-second deadlines pointed at endpoints that legitimately take longer — they generate steady 499 noise and can trigger false alarms.
  7. For POST and other writes, assume the request may have completed even though the client left. Make handlers idempotent or use idempotency keys before allowing retries.
  8. If you are the scraping client: raise timeouts before raising concurrency. More parallel requests against a slow target push latency up and generate 499s on their side and timeout exceptions on yours.
499 Client Closed Request

Proxies change your latency budget

Adding a proxy inserts extra network legs into every request: your client to the proxy endpoint, the proxy to its exit IP, the exit to the target, and the whole path back. Residential and mobile exits ride real consumer and carrier connections, so proxied round trips are naturally slower and more variable than direct ones. Keep the 5-second timeout you tuned for direct traffic and a healthy fraction of proxied requests will be aborted mid-flight — your logs fill with timeouts while the target's logs fill with 499s.

The fix is to size the budget to the path. Give proxied requests a read timeout that reflects the full round trip, reuse connections instead of paying setup costs on every request, and pick the exit type that matches your latency needs — ProxyOmega's sticky sessions and dedicated-speed tiers exist for exactly this trade-off.

Size timeouts to the path

For rotating residential traffic, a connect timeout around 10 seconds and a read timeout around 30 covers most scraping workloads. Split the two: fail fast on connection problems, but give the response time to travel the longer path.

Sticky sessions keep connections warm

Appending -session-<id> to the username holds the same exit IP for up to 24 hours, so keep-alive connections and TLS state get reused instead of renegotiated per request. Fewer cold starts means fewer requests brushing up against the deadline.

Pick exits for latency

Rotating pools trade speed for breadth. When response time is the constraint, Premium Unlimited's dedicated-speed residential ports (200 Mbps to 1 Gbps) or a dedicated Static ISP IP give a stable, faster path. Mobile's real 4G/5G carrier IPs sit at the slower end and are best reserved for targets that require them.

499 Client Closed Request

Set timeouts that fit a proxied round trip

This example splits connect and read timeouts, reuses one session over a sticky exit IP, and leaves room for a proxied response to arrive. If 499s at the target (and timeout exceptions on your side) persist with a 30-second read timeout, the endpoint itself is slow — reduce concurrency before shrinking anything.

import requests

sticky = "http://USERNAME-country-us-session-job42:[email protected]:10000"

session = requests.Session()
session.proxies = {"http": sticky, "https": sticky}
session.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"

# (connect timeout, read timeout): fail fast on connect,
# give the proxied response time to arrive
resp = session.get("https://example.com/api/items", timeout=(10, 30))
print(resp.status_code, resp.elapsed.total_seconds())
FAQ

Frequently asked questions

Can my HTTP client ever receive a 499 response?
Not from nginx — by definition the client is already gone when 499 is logged, so nothing is sent. What the client sees is its own error: a timeout exception, a cancelled request, or a closed socket. If you find a literal 499 in client-side code, some intermediate tool or framework generated it locally to represent the abort.
Does a 499 mean the server stopped processing my request?
Not reliably. The disconnect only stops the response from being delivered; the application behind the server may run the request to completion anyway. That matters for writes: a POST that logged 499 can still have created the order or record. Use idempotency keys or check state before re-sending anything with side effects.
Why did 499s spike after I routed my scraper through a proxy?
Each proxied request travels client to proxy to exit IP to target, which adds round-trip time. If you kept the timeout you tuned for direct requests, some responses now arrive after your deadline, your client aborts, and the origin logs 499. Raise the read timeout to fit the longer path and reuse sticky sessions so connections stay warm.
What is the difference between 499 and 408?
408 Request Timeout is a real response: the server sends it when the client took too long to finish sending its request. 499 is the mirror image and only a log entry: the client stopped waiting for the response and disconnected. With 408, the server gave up on you; with 499, you gave up on the server.

Give every request a budget it can meet. Start routing today.

Sticky sessions up to 24 hours and dedicated-speed residential ports keep proxied round trips inside your deadlines.

ProxyOmega ProxyOmega

90M+ ethically-sourced IPs across 200+ countries and 30,000+ cities. Residential, mobile, ISP and IPv6 proxies for scraping and AI agents.

GDPRCCPA
Product
Premium Unlimited Budget Unlimited Residential / ISP Mobile IPv6 Chrome Extension
Solutions
Web scraping AI agents Price monitoring SERP & SEO Integrations All use cases
Resources
Glossary Error codes Free tools Proxies by platform Locations
Company
About Blog Docs Reseller program Affiliate Contact Sign in
© 2026 ProxyOmega Ltd. All rights reserved.