HTTP 421 Misdirected Request: when a reused HTTP/2 connection reaches the wrong server

HTTP/2 can carry several origins on one connection, yet a server may still answer 421. What RFC 9110 and 9113 say about authority, connection reuse and retrying on a new connection.

http2rfc-9110rfc-9113networkprotocol

The certificate was valid and the TLS handshake succeeded, yet the response is 421 Misdirected Request. The server isn’t saying the resource is missing or that you lack permission. It’s saying this request came in over the wrong connection. To see why that happens, you need to know when an HTTP/2 client may send requests for several hostnames down one connection.

This post is based on RFC 9110 (HTTP Semantics, June 2022): Sections 4.3, 7.2, 7.3, 7.4, 9.2.2, 15.5.20, 17.1 and Appendix B.3. It also uses RFC 9113 (HTTP/2, June 2022): Sections 8.3.1, 9.1, 9.1.1, 10.1 and Appendix B. How browsers, HTTP libraries, CDNs and load balancers actually decide to reuse connections, or when they send 421, depends on the product, version and configuration. That isn’t covered here. Where something is this post’s own suggestion rather than an RFC rule, it says so.

What 421 means

RFC 9110 Section 15.5.20 defines it this way. 421 indicates that the request was directed at a server that is unable or unwilling to produce an authoritative response for the target URI. An origin server, or a gateway acting on behalf of the origin server, sends it in two situations.

  • The target URI doesn’t match any origin the server has been configured for (Section 4.3.1).
  • The target URI doesn’t match the connection context over which the request was received (Section 7.4).

The same section contains two rules.

  • A client that receives 421 MAY retry the request over a different connection, whether or not the method is idempotent. Examples given are a fresh connection specific to the target resource’s origin, or an alternative service.
  • A proxy MUST NOT generate a 421 response.

In other words, 421 isn’t a verdict on the resource. It’s a verdict on the pairing of the request with the connection. RFC 9110 Appendix B.3 says the same thing from another side. 421 was first defined in RFC 7540 (the original HTTP/2) and was moved into the core semantics because it applies more generally. In that move it also stopped being heuristically cacheable, because the response is specific to the connection, not to the target resource.

Origin and authority

The term the rules lean on is origin. RFC 9110 Section 4.3.1 defines a URI’s origin as the triple of scheme, host and port, after lowercasing the scheme and host and dropping leading zeros from the port. If the port is omitted, the scheme’s default is used. So https://Example.Com/happy.js has the origin { "https", "example.com", "443" }. Two origins are distinct if they differ in any one of scheme, host or port. Even when one entity controls both, their namespaces stay separate unless a server authoritative for that origin explicitly aliases them.

Authority is the question of whether a given server may answer for that origin. For https, Section 4.3.3 grounds it in the server’s ability to use the private key of a certificate the client trusts for that origin. Section 4.3.4 says the client MUST verify that the certificate’s identity is an acceptable match for the URI’s origin server. Name matching itself is covered in TLS certificate name mismatch.

Section 4.3.3 then draws the line that matters here.

  • In HTTP/1.1 and earlier, a client attributes authority to a server only over a secured connection established specifically to that URI origin’s host.
  • In HTTP/2 and HTTP/3, a client attributes authority to a server over an established, secured connection if the URI origin’s host matches any of the hosts in the server’s certificate, and the client believes it could open a connection to that host for that URI.

The RFC adds that in practice a client makes a DNS query to check that the origin’s host includes the same server IP address as the established connection. It also notes that the origin server can remove this restriction by sending an equivalent ORIGIN frame (RFC 8336). RFC 8336 isn’t among the sources for this post, so the ORIGIN frame isn’t discussed further.

When HTTP/2 shares one connection across origins

RFC 9113 Section 9.1 starts from the premise that HTTP/2 connections are persistent. Clients SHOULD NOT open more than one HTTP/2 connection to a given host and port pair. The host here can be derived from a URI, a selected alternative service, or a configured proxy. A client MAY open multiple connections to the same IP address and TCP port with different Server Name Indication (SNI) values or different TLS client certificates, but SHOULD avoid creating multiple connections with the same configuration.

Section 9.1.1 (Connection Reuse) sets the conditions for sharing a connection across hostnames.

  • A connection made to an origin server, directly or through a tunnel created with CONNECT, MAY be reused for requests with multiple different URI authority components. It can be reused as long as the origin server is authoritative (Section 10.1).
  • For TCP without TLS, this depends on the host having resolved to the same IP address.
  • For https resources, it additionally depends on having a certificate valid for the host in the URI. The certificate the server presented MUST satisfy any checks the client would perform when forming a new TLS connection for that host. A single certificate can establish authority for multiple origins.

RFC 9113 Appendix B notes that this concept, along with the 421 status code, now lives in RFC 9110, and calls it connection coalescing.

Why a valid certificate isn’t enough

Section 9.1.1 states the problem directly. In some deployments, reusing a connection for multiple origins can send requests to the wrong origin server. Its example is TLS termination performed by a middlebox that uses the SNI extension to select an origin server. Then a client can send requests to a server that may not be the intended target, even though the server is otherwise authoritative.

Here is that situation as a request flow. The names and the address are illustrations.

Certificate SAN: a.example.com, b.example.com
DNS: a.example.com -> 192.0.2.10
     b.example.com -> 192.0.2.10

client                 TLS terminator (192.0.2.10)        backends
  |-- TLS, SNI=a.example.com -->|-- route by SNI ------------> pool A
  |-- :authority=a.example.com  |--------------------------->  pool A  200
  |
  |  b.example.com: same cert, same IP -> client reuses the connection
  |-- :authority=b.example.com  |--------------------------->  pool A
  |<---------------------------- 421 Misdirected Request ----  pool A (not configured for b)
  |
  |-- new TLS, SNI=b.example.com -->|-- route by SNI --------> pool B
  |-- :authority=b.example.com      |----------------------->  pool B  200

From the client’s side, everything lines up. The certificate covers b.example.com and the addresses match, so the reuse conditions in RFC 9113 Section 9.1.1 are met. But the terminator decided where this connection goes once, at the handshake, based on SNI, so a request for b goes to pool A. If pool A isn’t set up for b, it’s in exactly the case Section 15.5.20 describes: unable to produce an authoritative response for the target URI. Section 9.1.1 names the way out: a server that does not want clients to reuse connections can indicate that it isn’t authoritative for a request by responding with 421.

RFC 9110 Section 4.3.3 places the responsibility for this on the origin side. Every service given control over the certificate’s private key should be equally responsible for the corresponding https namespaces, or at least prepared to reject requests that appear misdirected (Section 7.4).

What the server checks: the target URI and the connection context

RFC 9110 Section 7.4 describes what a server decides once it has parsed enough of a request to know its target URI. It can process the request, forward it, redirect it, respond with an error, or drop the connection. The decision can draw on anything about the request or connection, but is specifically about whether the server is configured for that target URI and whether the connection context suits the request.

  • One example of misdirection is a Host header field whose information differs from the connection’s host or port. From a trusted gateway this might be expected. Otherwise it might be an attempt to bypass security filters, get non-public content delivered, or poison a cache.
  • Unless the connection is from a trusted gateway, an origin server MUST reject a request if scheme-specific requirements for the target URI aren’t met. In particular, a request for an https resource MUST be rejected unless it arrived over a connection secured with a certificate valid for that target URI’s origin.
  • A 421 response indicates that the origin server rejected the request because it appears misdirected.

Section 4.3.3 adds a port example. If one host runs different services on 443 and 8000, the origin server needs to check the target URI even after the connection is secured, because a network attacker might cause a connection meant for one port to be received on the other. Without that check, a response for https://example.com/foo could be replaced with a seemingly authoritative response from https://example.com:8000/foo.

In HTTP/2, the request’s authority travels in the :authority pseudo-header field (RFC 9113 Section 8.3.1, RFC 9110 Section 7.2). A recipient MUST NOT use the Host header field to determine the target URI if :authority is present. A client MUST NOT generate a Host header field that differs from :authority, and a server SHOULD treat a request as malformed if they identify different entities. So the target URI the server compares against the connection comes from :authority.

Client retry: what is and isn’t allowed

The core rule is Section 15.5.20’s MAY. On 421, a client may retry over a different connection, regardless of whether the method is idempotent. A few things are easy to misread.

  • It’s MAY, not MUST. The RFC allows a retry but doesn’t require one.
  • The retry goes over a different connection. Sending the request again on the connection that just returned 421 isn’t what the rule permits. The RFC’s examples are a fresh connection specific to the target resource’s origin, or an alternative service.
  • Section 15.5.20 doesn’t give a reason for allowing non-idempotent methods. It fits Section 7.4’s description of 421 as the origin server having rejected a misdirected request, but the RFC doesn’t state outright that the request had no effect. Outside of 421, the general rule in RFC 9110 Section 9.2.2 applies: a client SHOULD NOT automatically retry a non-idempotent request unless it can know the semantics are idempotent or can detect that the original was never applied. The broader method rules are covered in Safe and idempotent HTTP methods.
  • The permission in Section 15.5.20 is written for “a client”. RFC 9110 doesn’t say how it combines with Section 9.2.2’s rule that a proxy MUST NOT automatically retry non-idempotent requests. This post’s conservative reading: an intermediary shouldn’t treat 421 as a reason to set that MUST NOT aside.
  • Section 15.5.20 doesn’t say what to do if the retry on a fresh connection also returns 421. Section 9.2.2 separately says a client SHOULD NOT automatically retry a failed automatic retry.

The function below sketches that decision. The rules come from the sections above; the shape of the function and the attempt counter are this post’s own.

interface RetryPlan {
  retry: boolean;
  newConnection: boolean; // open a fresh connection for this origin instead of reusing
}

function onMisdirected(
  status: number,
  attempt: number,         // 0 for the first send, 1 for the first automatic retry
  bodyReplayable: boolean, // can the request body be sent again from the start?
): RetryPlan {
  if (status !== 421) return { retry: false, newConnection: false };
  // 15.5.20: MAY retry over a different connection, idempotent or not
  // 9.2.2: SHOULD NOT automatically retry a failed automatic retry
  if (attempt >= 1 || !bodyReplayable) return { retry: false, newConnection: false };
  return { retry: true, newConnection: true };
}

bodyReplayable is an implementation precondition, not an RFC rule. A request body that was streamed out and discarded can’t be placed on a new connection. The function also leaves out where the new connection goes. If a fresh connection to the same address may hit the same terminator, a client needs to make sure SNI is set for the target origin’s host. RFC 9113 Section 9.1 allows multiple connections to the same IP and port with different SNI values.

How 421 differs from neighboring responses

  • 3xx redirects change the target URI. 421 keeps the URI and changes only the connection the request goes over. See HTTP redirects.
  • GOAWAY is a frame that shuts down the whole connection, and whether unfinished requests can be resent depends on the stream number in it. 421 is a normal response to one request, and the connection itself can keep serving other origins. See Retrying after HTTP/2 GOAWAY.
  • 425 Too Early concerns the replay risk of TLS 1.3 early data. It has nothing to do with sharing a connection across origins. See TLS 1.3 0-RTT and HTTP 425.
  • RFC 9110 Section 15.5.20 says a proxy MUST NOT generate 421. RFC 9113 Section 9.1.1 notes that a client configured to use a proxy over HTTP/2 sends every request through a single connection to that proxy. That is, all requests sent via a proxy reuse the connection to the proxy, and that kind of reuse isn’t what 421 deals with.

Operational checks

The following is this post’s suggestion, derived from the conditions above. It isn’t an RFC procedure, and none of it is based on measured data.

On the server or gateway side

  • Make the layer that decides routing compare the request’s :authority (or Host) with the context it decided on at the handshake. If a request arrives for a name the backend isn’t configured for, return 421 instead of serving another site’s content or returning 404. A 404 or 200 doesn’t give the client the “retry on a new connection” signal.
  • Return 421 from the origin server or from a gateway acting on behalf of the origin server. A proxy must not generate it (RFC 9110 Section 15.5.20).
  • Don’t let caches store a 421. It describes the connection, not the resource (RFC 9110 Appendix B.3).
  • To reduce cross-origin connection sharing in the first place, look at the reuse conditions. For https, reuse requires a certificate that is valid for the other host too (RFC 9113 Section 9.1.1). Bundling names that are routed to different places into one certificate creates the preconditions for reuse. Whether a given client actually reuses a connection when those preconditions hold depends on its implementation.

When you’re tracking down a 421

  • Check that the request’s target host and the hostname used to open the connection (SNI) are different. If your TLS terminator can log SNI, put it on the same line as :authority.
  • Check whether the certificate presented on that connection also includes the request’s host.
  • Check whether the two names resolve to overlapping addresses. RFC 9110 Section 4.3.3 describes this as the check clients do in practice.
  • Check whether the client retries on a new connection after 421, and whether that retry also returns 421. If the second attempt fails too, it’s likely that the new connection reaches the same backend.

Summary

From the RFCs

  • 421 means the server can’t or won’t give an authoritative response for the target URI on this connection. It’s about the pairing of request and connection, not the resource.
  • An HTTP/2 connection may be reused for multiple origins as long as the server is authoritative. For https, that requires a certificate valid for the other host as well.
  • When a TLS terminator routes by SNI, a reused connection can reach a server that isn’t the intended target. The server can refuse with 421.
  • A client may retry after 421 over a different connection, even with a non-idempotent method. A proxy must not generate 421, and 421 isn’t heuristically cacheable.

Suggestions from this post

  • Have the routing layer return 421 when :authority doesn’t fit the connection.
  • Retry on a new connection only once, and only when the body can be replayed.
  • When tracking a 421, look at SNI, :authority, the certificate’s names and the DNS answers together.

Sources and check date

All checked on 2026-10-27.

Back to the blog