Safeguard
Security Guides•

Which timeouts should a Go HTTP server set?

Which timeouts does a Go net/http server need? Set ReadHeaderTimeout, IdleTimeout and a write limit, because ListenAndServe applies none by default.

Safeguard Security Team
4 min read

A Go HTTP server should set ReadHeaderTimeout, IdleTimeout and WriteTimeout on a http.Server value, and usually ReadTimeout too. The package-level ListenAndServe helper builds a Server with none of them set, and the documented zero value means no timeout, so a slow client can hold a connection open indefinitely.

What the zero value means

The Go source documents each field on http.Server. For ReadTimeout, WriteTimeout and IdleTimeout, "a zero or negative value means there will be no timeout", and ReadHeaderTimeout falls back to ReadTimeout when it is zero. The helper function is two lines long: it creates a Server with only an address and a handler, then calls its ListenAndServe method.

That is fine on a laptop. On the internet it means a client can send one header byte every few seconds and keep a goroutine and a file descriptor busy for as long as it likes. This is the slow header pattern, often called Slowloris.

The four fields, in plain words

FieldWhat it limitsZero means
ReadHeaderTimeoutTime to read the request headersFalls back to ReadTimeout, else none
ReadTimeoutTime to read the whole request, body includedNone
WriteTimeoutTime before response writes time out, reset when a new request header is readNone
IdleTimeoutWait for the next request on a keep alive connectionFalls back to ReadTimeout, else none

The Go source also notes that ReadTimeout does not let a handler decide a per request deadline or upload rate, so most users prefer ReadHeaderTimeout. It is valid to use both. MaxHeaderBytes caps header size, and the source says it does not limit the request body. When it is zero, DefaultMaxHeaderBytes applies, which the source defines as 1 MB.

A starting configuration

srv := &http.Server{
    Addr:              ":8443",
    Handler:           mux,
    ReadHeaderTimeout: 5 * time.Second,
    ReadTimeout:       30 * time.Second,
    WriteTimeout:      60 * time.Second,
    IdleTimeout:       120 * time.Second,
    MaxHeaderBytes:    64 << 10,
}

These numbers are a starting point, not a standard. Choose them from your slowest legitimate request. A file upload endpoint needs a longer ReadTimeout than a JSON API, and a streaming endpoint may need WriteTimeout raised or handled per request. Measure first, then tighten.

Steps to apply this

  1. Replace every call to the package level ListenAndServe or ListenAndServeTLS with an explicit http.Server value.
  2. Set ReadHeaderTimeout first. It is the cheapest protection and rarely breaks real clients.
  3. Add IdleTimeout so abandoned keep alive connections are released.
  4. Set WriteTimeout and ReadTimeout from measured request durations, and handle long running routes separately.
  5. Lower MaxHeaderBytes if your clients send small headers.
  6. Put a body size cap on handlers that read bodies. See the post on limiting request bodies with MaxBytesReader.

If a reverse proxy sits in front, the proxy has its own limits, but the Go server should not rely on that. A direct connection from another pod, a sidecar or a misconfigured route skips the proxy.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how a running web app is probed from the outside, which is where missing server limits show up.

Quick check

Does http.TimeoutHandler replace server timeouts?

No. TimeoutHandler runs a handler with a time limit and answers 503 when it is exceeded, but it does not limit how long a client takes to send headers. Use both.

Is ReadTimeout enough on its own?

It covers the whole request including the body, so it can cut off slow legitimate uploads. ReadHeaderTimeout plus a per request body policy is more flexible.

Safeguard's dependency scanning and SBOM generation cover the Go modules your service builds from, with reachability analysis to separate reachable findings, and the free scan is at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.