Short answer
ERR_QUIC_PROTOCOL_ERROR means Chrome reached the site over QUIC (HTTP/3, which runs on UDP port 443) and that connection broke in a way Chrome could not recover from. If only you see it, a VPN, antivirus, extension or network filter is interfering with UDP. If every visitor sees it, check the site’s HTTP/3 setup.Where to start
- If it happens on one device, on every networkcheck extensions, VPN, proxy and antivirus on that device
- If it happens only on one network, such as an office, school or VPNthat network breaks QUIC; test from mobile data
- If every visitor sees it on your own sitetest HTTP/3 from a second machine
- If your site runs behind Cloudflareswitch Cloudflare’s HTTP/3 off to confirm
What ERR_QUIC_PROTOCOL_ERROR means
Chrome loads many large sites over HTTP/3 (Google, YouTube, sites behind Cloudflare). HTTP/3 does not use TCP: it runs on QUIC, a transport built on UDP that carries TLS 1.3 inside it. A server announces that it speaks HTTP/3 with an Alt-Svc response header over a normal HTTPS connection, or the domain lists h3 in an HTTPS record in DNS. Chrome remembers the announcement and opens a QUIC connection to UDP port 443. For how TCP differs, see what TCP is and how it works.
Key facts
- Chrome error code
- -356net_error_list.h: "There is a QUIC protocol error."
- Transport
- UDP 443Regular HTTPS uses TCP 443
- How servers announce it
- Alt-Svc: h3=":443"
- Standards
- QUIC RFC 9000 (2021), HTTP/3 RFC 9114 (2022)
- nginx support
- 1.25.0+, built with --with-http_v3_module
- Browsers that show this code
- Chrome, Edge, Brave, Opera (Chromium)
The code is rarer than the number of sites on HTTP/3 suggests, because Chrome has a safety net. When a QUIC connection fails, Chrome normally retries the request, over TCP if it has to, and you never notice. In Chromium’s http_network_transaction.cc that retry is skipped in three cases: the response had already started to arrive, two retries were already used, or the request was not on an announced alternative service. So the error usually means a QUIC connection that worked and then died mid-way: a filter that drops UDP after a few seconds or a few megabytes, a VPN that mangles UDP, or a server that cuts the connection.
That is also why a closed UDP port alone rarely causes it. If nothing answers on UDP 443, the QUIC attempt fails before any data flows, Chrome uses TCP, and the page simply loads a little slower.
| Code | Chrome error | What it points to |
|---|---|---|
| -356 | ERR_QUIC_PROTOCOL_ERROR | An established QUIC connection broke; this article |
| -358 | ERR_QUIC_HANDSHAKE_FAILED | The QUIC handshake failed, the server read no request |
| -380 | ERR_QUIC_CERT_ROOT_NOT_KNOWN | The certificate on the QUIC connection does not chain to a known root |
| -337 | ERR_HTTP2_PROTOCOL_ERROR | The same kind of failure on HTTP/2 over TCP |
| -107 | ERR_SSL_PROTOCOL_ERROR | The TLS handshake over TCP failed: ERR_SSL_PROTOCOL_ERROR |
| -101 | ERR_CONNECTION_RESET | A TCP reset killed the connection: ERR_CONNECTION_RESET |
Codes and descriptions are from Chromium’s net_error_list.h. On a full page you see This site can’t be reached with the code underneath. When only a video, image or script fails, the page loads and the DevTools console shows Failed to load resource: net::ERR_QUIC_PROTOCOL_ERROR instead. Firefox and Safari use their own error texts for QUIC failures.
Fixes for visitors: your browser and device
Work through these in order and reload the page after each one. All of them are easy to undo.
- Open the page in an Incognito window. Extensions are off there unless you allowed them. If the page loads, open
chrome://extensions, switch everything off and turn extensions back on one at a time. Ad blockers, VPN add-ons and “privacy” extensions that rewrite requests are the usual suspects. - Disconnect the VPN and turn off any proxy. Many VPNs handle UDP differently from TCP, and some break long QUIC transfers. On Windows the proxy lives under Settings → Network & internet → Proxy; on a Mac under System Settings → Network → your connection → Details → Proxies.
- Pause antivirus web protection for one test. Products that inspect HTTPS often cannot read QUIC. If the page then loads, add an exception for the site and switch the protection back on.
- Update Chrome under
chrome://settings/helpand restart it. QUIC bugs on Chrome’s side get fixed in normal updates.
If none of that helps, switch QUIC off as a test: open chrome://flags/#enable-quic, set Experimental QUIC protocol to Disabled and click Relaunch. In Edge the address is edge://flags/#enable-quic. If the page now loads, you have confirmed that QUIC is the problem, and Chrome is on HTTP/2 over TCP for every site. Set the flag back to Default once you have found and fixed the cause, because the flag hides the symptom on this one browser only.
To see which protocol a page really used, open DevTools (F12), go to the Network tab, right-click a column header and enable Protocol. HTTP/3 requests show as h3, HTTP/2 as h2. For a deeper look, record a log at chrome://net-export while you reproduce the error.
When only one network is affected
If the site works over your phone’s mobile data but fails on the office, school or hotel network, that network is the cause. Many company firewalls block or inspect QUIC on purpose so they can filter traffic. A clean block is harmless, because Chrome falls back to TCP. The error appears when a device lets QUIC start and then drops it, for example after a UDP rate limit or a session timeout.
- On your own router or firewall: allow outgoing UDP to port 443, or block it outright. Both are fine for browsing; a half-working rule is not.
- On a managed network: tell the network team which site fails and that the error is
ERR_QUIC_PROTOCOL_ERROR. They can allow UDP 443 for it or block QUIC cleanly, which ends the error for everyone on that network. - Errors on every network and every site? Then it is your device after all; go back to the visitor fixes. A related code on laptops that switch networks is
ERR_NETWORK_CHANGED.
Site owners: test HTTP/3 from outside
If visitors report the error on your site, find out first whether you serve HTTP/3 at all. Every HTTPS response that offers it carries an Alt-Svc header. This works with any curl:
curl -sI https://example.com/ | grep -i '^alt-svc'curl.exe -sI https://example.com/ | findstr /i alt-svcReal output from two large sites that serve HTTP/3 (curl 7.88.1, 02.11.2026):
$ curl -sI https://www.google.com/ | grep -i '^alt-svc'
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
$ curl -sI https://www.youtube.com/ | grep -i '^alt-svc'
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000h3=":443" means “HTTP/3 is on UDP port 443 of this host”, ma is how many seconds browsers may remember that (2592000 is 30 days), and h3-29 is an old draft version some servers still announce. Chrome also starts QUIC when the domain publishes an HTTPS record in DNS whose alpn lists h3, so check that too:
dig +short HTTPS example.com$ dig +short HTTPS www.google.com
1 . alpn="h2,h3"No Alt-Svc line and no HTTPS record that lists h3 means the site does not offer HTTP/3, so Chrome never tries QUIC for it and this error cannot come from your server.
Without a terminal, our HTTP header checker shows the response headers of any URL, including Alt-Svc when the server sends one.
Then make a real HTTP/3 request. --http3-only (curl 7.88.0 and later) fails when no QUIC connection can be made, while --http3 quietly falls back to older versions and proves nothing. Run it from a second machine, such as another VPS or your laptop, not from the server itself, so the request crosses the same firewalls a visitor crosses:
curl -V | grep -o HTTP3
curl --http3-only -sS -o /dev/null -w '%{http_version}\n' https://example.com/The first line must print HTTP3; the second prints 3 when the request went over QUIC. Not every curl can do this. Debian 12’s curl 7.88.1 has no HTTP/3 support and stops right away:
$ curl --http3-only -sI https://www.google.com/
curl: option --http3-only: the installed libcurl version doesn't support this
curl: try 'curl --help' or 'curl --manual' for more informationDebian 13’s libcurl package is built against nghttp3; check curl -V there for HTTP3 in the Features line. Interpret the result like this:
Alt-Svcor anh3HTTPS record present,--http3-onlyfails: you announce HTTP/3 but it is not reachable. Check the firewall and the nginx listener.- Both work, but large pages or downloads fail: QUIC dies mid-transfer. Look for a UDP rate limit or DDoS filter in front of the server, and for config reloads during the failures (nginx section).
- Everything works from outside: the problem is on the visitors’ side, so point them to the visitor fixes.
Open UDP port 443 in the firewall
The classic server-side mistake: TCP 443 is open, UDP 443 is not. It is easy to miss, because the profiles people copy only cover TCP. On Debian and Ubuntu, the Nginx Full profile that the nginx package installs for ufw reads ports=80,443/tcp, so ufw allow 'Nginx Full' leaves QUIC blocked. On Debian 13, sudo ufw allow "Nginx QUIC" opens TCP 80/443 and UDP 443 in one step; Debian 12 and Ubuntu 24.04 have no such profile. Check and open the port:
sudo ufw status verbose | grep 443
sudo ufw allow 443/udpsudo iptables -S INPUT | grep 443
sudo iptables -I INPUT -p udp --dport 443 -j ACCEPTudp dport 443 acceptRules added with iptables are lost on reboot unless you save them (for example with netfilter-persistent save on Debian). ufw keeps its rules, and the general ufw workflow is in our ufw firewall setup guide. If your provider has a firewall in its control panel or a cloud security group, allow UDP 443 there as well; it filters before your server sees anything.
Most online port checkers, including our port checker, test TCP. They report 443 as open even when UDP 443 is closed, so use the curl test above for QUIC.
Confirm that nginx actually listens on UDP 443, not just TCP:
sudo ss -ulnp 'sport = :443'
sudo ss -tlnp 'sport = :443'The first command must list nginx (as UNCONN, since UDP has no connections). An empty result means no QUIC listener: see the next section. For more ways to read listening ports, see how to check open ports on Linux.
nginx HTTP/3 configuration check
nginx speaks HTTP/3 since 1.25.0, through ngx_http_v3_module, which the docs still call experimental and which is not built by default. Check your binary first:
nginx -v
nginx -V 2>&1 | grep -o with-http_v3_moduleNo output from the second line means no HTTP/3. Distribution packages differ: Debian 12 ships nginx 1.22.1 and Ubuntu 24.04 ships 1.24.0, both older than 1.25.0, so neither can serve HTTP/3. Debian 13 ships 1.26.3, built with --with-http_v3_module. On Debian 12 and Ubuntu 24.04 the packages from nginx.org are the usual way to get 1.25 or later. With the distribution’s nginx package, a Debian 12 or Ubuntu 24.04 server should not send an Alt-Svc: h3 header at all; if it does, something else (a CDN, a copied snippet) adds it.
A working setup on nginx 1.25.1 or later looks like this:
server {
listen 443 quic reuseport;
listen 443 ssl;
listen [::]:443 quic reuseport;
listen [::]:443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# tells browsers HTTP/3 is on UDP 443; "always" also adds it to error responses
add_header Alt-Svc 'h3=":443"; ma=86400' always;
}The mistakes that break it:
reuseporton more than one server block. Socket options such asreuseportmay appear only once per address and port. Putlisten 443 quic reuseport;in one server block and plainlisten 443 quic;in all the others, ornginx -trefuses the config.- A QUIC listener without the TCP one. Browsers learn about HTTP/3 over a normal HTTPS connection first, so
listen 443 ssl;must stay. Alt-Svcpointing at the wrong port. The port inh3=":443"must be the port of thequiclistener.- The header vanishes in some locations. nginx inherits
add_headeronly into blocks that define noadd_headerof their own. Alocationthat sets, say, a cache header dropsAlt-Svcunless you repeat it there. - Transfers that break on reload. Since nginx 1.31.7,
quic_bpf on;keeps established QUIC connections through a configuration reload. It goes in the main context (outsidehttp), needs Linux 5.7 or later, and a reload cannot switch it on: restart nginx once after adding it. Without it, expect long-running QUIC downloads to fail when you reload, which visitors see as this error.
Test and apply the change:
sudo nginx -t && sudo systemctl reload nginxIf you cannot fix HTTP/3 right away, remove the Alt-Svc line and reload, and remove h3 from any HTTPS record in your DNS. New visitors stay on HTTP/2 over TCP. Browsers that already cached the old header try QUIC until its ma time runs out, but as soon as QUIC fails before any data arrives they use TCP. More on reloads in how to restart nginx, and on TLS in front of an app in nginx as a reverse proxy with SSL.
Behind Cloudflare
With the orange cloud on, visitors talk QUIC to Cloudflare, not to your server. Cloudflare’s docs say HTTP/3 to the origin is not supported, so Cloudflare reaches your server over HTTP/1.1 or HTTP/2 on TCP. Your nginx HTTP/3 settings and your UDP 443 rule therefore play no part in an ERR_QUIC_PROTOCOL_ERROR on a proxied hostname.
To confirm that QUIC is the trigger, turn it off for a moment: in the dashboard, open your zone, then Speed → Settings → Protocol Optimization and switch HTTP/3 off. If the reports stop, the problem sits between the visitors and Cloudflare (often one ISP or one corporate network). Collect the affected networks before you switch HTTP/3 back on, since it helps everyone else. An error page from Cloudflare with a number, such as error 520 or error 522, is a different problem between Cloudflare and your server; a timeout from a closed TCP port looks like ERR_CONNECTION_TIMED_OUT.
Symptoms, causes and fixes at a glance
Symptom, cause, fix
Symptom: Every QUIC site fails on one PC, other devices are fine
- Cause
- An extension, VPN client, proxy or antivirus on that device handles UDP badly.
- Fix
- Test in Incognito, then without VPN and with web protection paused. Use
chrome://flags/#enable-quiconly to confirm.
Symptom: Fails on the office or school Wi-Fi, works over mobile data
- Cause
- A firewall on that network lets QUIC start and then drops it.
- Fix
- Ask the network team to allow UDP 443 or block QUIC cleanly; on your own router, do one of the two.
Symptom:
Alt-Svc: h3is sent,curl --http3-onlyfails from outside- Cause
- UDP 443 is closed in ufw, iptables or a provider firewall, or nginx has no quic listener.
- Fix
Debian · Ubuntu sudo ufw allow 443/udp # Debian 13: or sudo ufw allow "Nginx QUIC" sudo ss -ulnp 'sport = :443'
Symptom: Small pages load, large downloads or videos fail with
net::ERR_QUIC_PROTOCOL_ERROR- Cause
- A UDP rate limit or DDoS filter in front of the server, or nginx reloads during transfers.
- Fix
- Raise or exempt UDP 443 in the filter; schedule reloads; remove Alt-Svc (and h3 in a DNS HTTPS record) until it is fixed.
Symptom: Proxied site behind Cloudflare, reports from some visitors only
- Cause
- QUIC fails between those visitors and Cloudflare; your origin is not involved.
- Fix
- Switch HTTP/3 off under Speed → Settings → Protocol Optimization to confirm.
Should you disable QUIC?
As a visitor, only as a test or as a stopgap on a network you cannot change. Chrome works fine over HTTP/2, but HTTP/3 copes better with lost packets and changing networks, and the flag stays off for every site until you reset it. As a site owner, switching HTTP/3 off is a fair temporary fix while you open UDP 443 or repair the config, because no visitor loses access: everyone falls back to TCP. For background on the two ports a web server needs, see ports 443 and 80.
Running HTTP/3 yourself needs a server where you control the firewall and the nginx build. A VMHeaven Standard KVM gives you root, so you can open UDP 443, install the nginx version you need and watch ss and the logs yourself, and the VNC console in the panel still reaches the machine if a firewall rule locks you out.
How we tested
- OS image
- Debian 12.15
- Versions
- curl 7.88.1dig 9.18.49nginx-common 1.22.1-9+deb12u10
- Tested on
- Method
- Read the Alt-Svc headers of public HTTP/3 sites with curl and their DNS HTTPS records with dig, ran curl --http3 and --http3-only against Debian 12's curl (the --http3-only refusal is shown; --http3 fails the same way) and read the ufw profile that nginx-common installs. The nginx HTTP/3 config follows nginx.org; we did not run an HTTP/3 server for this article.
Frequently asked
How do I fix ERR_QUIC_PROTOCOL_ERROR in Chrome?
Open the page in an Incognito window to rule out extensions, then disconnect any VPN or proxy and pause antivirus web protection for one test. If the error only appears on one network, that network breaks QUIC; try mobile data. Disabling chrome://flags/#enable-quic confirms the cause, but set it back to Default once the real cause is fixed.
What causes ERR_QUIC_PROTOCOL_ERROR?
A QUIC connection (HTTP/3 over UDP port 443) that broke after it had started. Typical causes are VPNs, antivirus or extensions that handle UDP badly, firewalls that let QUIC start and then drop it, and on the server side a UDP rate limit, a half-finished nginx HTTP/3 setup or reloads during long transfers.
Is it safe to disable QUIC in Chrome?
Yes. Chrome then uses HTTP/2 or HTTP/1.1 over TCP, and every site keeps working. You lose HTTP/3's better handling of packet loss and network changes, and the flag stays off for all sites, so use it as a test or a stopgap and switch it back to Default later.
Do I need to open UDP port 443 for HTTP/3?
Yes. HTTP/3 runs over QUIC on UDP, so a server that announces HTTP/3 with an Alt-Svc header or a DNS HTTPS record needs UDP 443 open in ufw, iptables or nftables and in any provider firewall, plus an nginx listener with the quic parameter. The ufw profile Nginx Full opens only TCP 443; on Debian 13 the Nginx QUIC profile also opens UDP 443.