RUEN

How it works

QUIC blocked on your network: why Hysteria2 fails and VLESS over TCP still works

8 min read

Hysteria2 works everywhere except one network, and on that network VLESS Reality connects without complaint. That is usually not a broken server or an expired subscription. It is the difference between UDP and TCP, and networks that treat the two differently are far more common than protocol comparisons suggest.

QUIC is the transport underneath HTTP/3 and underneath Hysteria2. Both ride on UDP. Where a network is hostile to UDP, both fail in the same way - which is useful, because the browser then gives you a free diagnostic.

Why UDP is treated differently from TCP

A TCP flow announces itself. There is a SYN, an established state, a FIN or an RST at the end. Any middlebox in the path can build a table of live connections, age entries out correctly and apply policy per connection. UDP offers none of that: no handshake to observe, no end-of-flow signal. Equipment has to guess when a mapping is dead.

The consequences are practical rather than ideological:

  • NAT mappings for UDP expire on a timer. RFC 4787 asks for at least two minutes and recommends five or more; plenty of home routers and carrier-grade NATs are more aggressive than that. An established TCP connection, by contrast, is expected to survive hours of idling.
  • Firewall defaults are asymmetric. Outbound TCP to 80 and 443 is permitted almost everywhere. Outbound UDP is often restricted to DNS, NTP and whatever the phone system needs.
  • UDP is the amplification transport. DNS, NTP and memcached reflection all ride on it, so mitigation rules are quick to rate-limit unsolicited UDP and slow to touch TCP.
  • Inspection stacks handle QUIC differently. With a corporate root certificate installed, a proxy can terminate a TLS session inside TCP and read it; mainstream inspection products do not do the equivalent for QUIC. They can still recognise a QUIC flow, and the server name in the first Initial packet is recoverable, but the session contents stay out of reach - so the simpler policy is to drop it and let the client fall back.

The reasons operators actually give

Blocking QUIC is rarely aimed at tunnels. In most cases it is a documented setting on the box, switched on for a reason the operator would state openly:

  • Corporate and campus networks. Policy requires TLS inspection or category filtering on web traffic. QUIC defeats both, so UDP/443 is dropped and browsers fall back to HTTP/2 over TCP, where the inspection works. The major firewall vendors ship a named application signature for QUIC so that this rule is one click.
  • Hotels, airports, in-flight Wi-Fi, captive portals. A minimal allowlist: TCP 80 and 443 plus DNS. Nothing else was considered.
  • Mobile carriers and CGNAT. Less a block than a small budget - UDP mappings are short-lived and the state table is shared by a lot of subscribers.
  • Hosting-side scrubbing. Your provider’s DDoS protection may rate-limit inbound UDP to your address by default. This one sits on the server side and you can usually change it.
  • Congestion management. Some links deprioritise UDP when they are busy, on the old assumption that UDP is not congestion-controlled.
Some networks go further and reach only a named set of destinations - mobile networks in Russia have operated that way during regional restrictions. There, UDP to an arbitrary address stops working early, and so does most traffic to any host that is not on the list. That is a property of the network you are attached to, not of your client, and no transport setting changes it.

Why Hysteria2 fails on exactly those networks

Hysteria2 is QUIC over UDP by design and has no TCP mode to fall back to. When a browser meets a QUIC block it retries over TCP almost immediately and you never notice. A Hysteria2 client has nowhere to retry, so the same network condition surfaces as a hard failure at the handshake.

Two design choices make it stand out more than ordinary HTTP/3 traffic:

  • Congestion control. Hysteria2 uses Brutal whenever you declare up and down bandwidth in the config, and standard BBR when you leave those fields empty. Brutal sends at the rate you declared and does not back off on loss the way TCP and BBR do. On a genuinely lossy link that is the point of the protocol. On a link with a policer, a flow that holds its rate while packets are being dropped is precisely the shape a rate-limiter exists to punish.
  • Traffic profile. A steady, long-lived, high-rate UDP flow to one host on one port is not what browsing over HTTP/3 looks like. Masquerading as an HTTP/3 file server, which Hysteria2 can do, answers a prober knocking on the port. It does nothing about a rule that drops UDP/443 wholesale.

So a Hysteria2 failure is not by itself evidence that the protocol was recognised and targeted. Far more often it means UDP never left your network, and the server never heard from you at all.

Why VLESS over TCP usually survives

VLESS Reality runs over TCP 443, and its handshake copies that of a real public site. Any network that lets people browse the web has to allow outbound TCP 443, and the flow does not stand out from everything else on that port. That is the whole reason the TCP profile keeps working on networks where the UDP one dies. The two are compared side by side in the guide on VLESS Reality vs Hysteria2, and the handshake itself is covered in what VLESS Reality is.

It is not universal. Three cases take TCP down as well:

  • Mandatory TLS inspection. On a managed device with a corporate root certificate installed, a proxy terminates every TLS session on 443. Reality authenticates the server, so an interposed session fails to come up rather than being quietly read. If that is your employer’s device and policy, it is a conversation for your IT department, not a setting to work around.
  • Networks whose only egress is an explicit proxy. Direct outbound 443 to an arbitrary address is dropped and everything has to go through a configured HTTP proxy, so what gets through depends on what that proxy permits in a CONNECT request.
  • Allowlist networks. If only a named set of destinations is reachable, an unlisted host on TCP 443 is no more reachable than the same host on UDP 443.

Two MTU problems that get confused with each other

The first is QUIC’s own floor. RFC 9000 forbids using a path that cannot carry a 1200-byte UDP payload, the client pads its first Initial packet up to that size, and endpoints are told to set the do-not-fragment bit. If something in the path cannot carry that and the ICMP message that should report it is filtered - which is common - the very first packet disappears with no error anywhere. From the client, that is indistinguishable from a block by timing: nothing ever comes back. It is the single most common way a UDP-block diagnosis goes wrong.

The second is the tunnel MTU, and it is the one people usually mean. Once the tunnel is up, the virtual interface has to leave room for the outer headers. Set it too high and the connection establishes, small requests pass, and any large transfer stops at the same point every time. This one hits TCP inside the tunnel as much as UDP, so it is not evidence about the transport at all.

  • Typical causes: a PPPoE link, a tunnel running inside another tunnel, some mobile APNs, an IPv6 path where the 1280-byte minimum is already tight once outer headers are added.
  • Typical fix: lower the MTU on the client tunnel interface and retry. In sing-box that is the mtu field on the tun inbound.
  • Why plain TCP outside a tunnel usually escapes both: each end advertises an MSS during the handshake, and the same links that break large datagrams commonly clamp that MSS on the way through. Encrypted tunnel payload gives them nothing to clamp.

Telling a block, a shaper and a dead mapping apart

Five different faults get reported with the same sentence - it does not work. Most of them separate on timing alone:

  • Nothing from the first packet, identical on every UDP port and every server you try. That is a block - or a path that cannot carry a 1200-byte datagram, which looks the same from here. The path MTU measurement below is what tells them apart.
  • Connects normally, runs, then settles at a flat low ceiling - the same ceiling every time, regardless of server or time of day. That is a shaper or a policer, not a block.
  • Runs, goes quiet after a short idle period, recovers the instant you send something. That is a NAT mapping timing out: until your client opens a new one, nothing from the server side has anywhere to arrive.
  • Comes up, small requests are fine, large transfers stall at the same point every attempt. That is the tunnel MTU, described above.
  • Works on Wi-Fi and fails on mobile data, or the reverse, with the same config. That is per-network policy - compare the two networks before touching the server.

How to test which case you are in

  1. 1Check whether QUIC works for ordinary traffic, using a site you know serves HTTP/3. Load it twice: a browser learns about HTTP/3 from an Alt-Svc header on a response that arrived over TCP, so h2 on a first visit proves nothing. On the second load, h3 in the protocol column of the network panel means UDP/443 is getting through.
  2. 2Read the client log instead of the connect button. A Hysteria2 or sing-box client reporting timeout: no recent network activity during the handshake never received a single packet back.
  3. 3Measure the path before blaming a filter. tracepath <server> on Linux reports the path MTU; failing that, send a do-not-fragment probe of the right size - ping -M do -s 1272 <server> on Linux, ping -D -s 1272 <server> on macOS. If the small probe answers and that one does not, QUIC is hitting a size limit rather than a policy. If ICMP is filtered outright, this test tells you nothing either way.
  4. 4Capture on the server if you run it yourself: sudo tcpdump -ni any udp port 443. If your packets appear there, the outbound path is fine and the problem is on the return leg or in the server config. If nothing appears, they are being dropped between you and the server - which covers both a filter and a size limit, hence the previous step.
  5. 5Separate a port rule from a blanket rule. Move the endpoint to a different UDP port and retry. One port working while another does not means a per-port rule, not a ban on UDP as such.
  6. 6Separate a block from shaping. Run a long transfer rather than a speed test. A block fails at the handshake; shaping connects cleanly and then flattens out once the transfer has been running for a while.
  7. 7Compare against the TCP profile on the same network within the same minute. VLESS Reality connecting while Hysteria2 does not is the clearest signal that the transport is the variable, not the server.

Only the packet capture needs access to the server. Everything else runs from the client and still narrows the problem down to the transport, which is the decision you actually need to make.

What to do about it

  • Switch to the TCP profile. On a network that filters UDP, that is the entire answer.
  • Try another UDP port before writing UDP off. Port hopping helps against per-port rules and per-flow rate limits, and does nothing against a blanket UDP drop.
  • Shorten the keepalive interval if the symptom is idle death, so the mapping gets refreshed before the NAT discards it. In Hysteria2 that is quic.keepAlivePeriod in the client config.
  • Lower the tunnel MTU if the symptom is large transfers stalling at a fixed point.
  • Check the hosting provider’s inbound UDP rules if the server sees nothing from anyone, not only from you.
  • Disable HTTP/3 in the browser on a network that half-breaks QUIC - otherwise every new origin costs a failed QUIC attempt before the fallback.
  • Stop tuning once you have established that the network only reaches a named set of destinations. At that point the transport is not the variable, and no client setting is either.
None of this is about anonymity. Both transports replace your visible network address and encrypt traffic to the server; neither makes you anonymous, and switching between them changes nothing on that front. That distinction is covered in the guide on what a VPN does and does not hide.

Is QUIC blocked because it is used for VPNs?

Usually not. The common reasons are inspection and manageability: an appliance that has to filter or log web traffic cannot read inside a QUIC session, so it drops UDP/443 and lets browsers fall back to TCP, where it can. Tunnels are collateral damage in that rule rather than its target.

Does port hopping get around a UDP block?

Only if the block is per-port. Where the rule is on UDP as a protocol, or where the network reaches only a named set of destinations, hopping ports changes nothing. It genuinely helps against per-flow rate limiting and against rules written for a single well-known port.

Should I turn off HTTP/3 in my browser on such a network?

It often helps. Chrome and Firefox keep attempting QUIC per origin and falling back, and each attempt costs time. In Chrome the switch is on chrome://flags under Experimental QUIC protocol; in Firefox it is network.http.http3.enable in about:config. Turn it back on when you leave the network.

Hysteria2 connects but collapses to a few megabits. Is that a block?

No, that is shaping. A block fails at the handshake. A stable, repeatable low ceiling that appears after a period of normal speed points at a policer on the path, and Brutal congestion control makes a flow more visible to one, not less. Lowering the declared bandwidth sometimes helps; moving to TCP usually helps more.

The ISP says nothing is blocked, and QUIC still fails. Who is right?

Both can be. Carrier-grade NAT with short UDP timers, upstream DDoS scrubbing on the hosting side and a path that cannot carry a 1200-byte datagram all produce failures that nobody configured deliberately and that no support desk has a record of. The path MTU check and the server-side capture are what settle it.