RabbitMQ Error Guide: 'closing AMQP connection ... {bad_header,...}' — Fix Protocol Mismatch
Fix RabbitMQ 'bad_header' handshake errors: stop clients speaking HTTP, TLS, or the wrong AMQP version to port 5672, point them at the right listener and TLS port, and clear the noise.
- #rabbitmq
- #messaging
- #troubleshooting
- #errors
Stuck on this RabbitMQ error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
Every AMQP 0-9-1 connection begins with the client sending an 8-byte protocol header — the literal bytes AMQP followed by the protocol version — so the broker can confirm it’s talking to a real AMQP client before doing anything else. When the first bytes on the socket are not a valid AMQP header, RabbitMQ rejects the connection during the handshake and logs a bad_header error naming the bytes it actually received:
=ERROR REPORT====
closing AMQP connection <0.1234.0> (10.0.4.7:52233 -> 10.0.2.9:5672):
{bad_header,<<"GET / HT">>}
The <<"GET / HT">> is the give-away: those are the first eight bytes of an HTTP request (GET / HTTP/1.1) arriving on the AMQP port. A TLS client hitting the plaintext port produces a binary header variant instead:
closing AMQP connection <0.1250.0> (10.0.4.7:52240 -> 10.0.2.9:5672):
{bad_header,<<22,3,1,0,242,1,0>>}
Byte 22 (0x16) is the TLS handshake record type — a TLS client tried to negotiate on the plaintext AMQP listener. In all cases the meaning is the same: whatever connected is not speaking plain AMQP 0-9-1 on that port.
Symptoms
- The broker log fills with
{bad_header,...}entries, each closing a connection immediately after it opens. - Clients report the connection is dropped right after connect, often as a generic “connection reset” or “broken pipe”, with no authentication ever attempted.
- A browser or
curlpointed athttp://broker:5672hangs or returns nothing, and a matching{bad_header,<<"GET / HT">>}appears in the log. - A health checker, load balancer probe, or port scanner repeatedly triggers the error at a fixed interval.
- Applications using a TLS AMQP URI (
amqps://) against the non-TLS port 5672 fail instantly, whileamqp://to the same port works. - No
user authenticationoraccess refusedmessages accompany it — the failure is earlier than login, at the protocol handshake.
Common Root Causes
- HTTP traffic on the AMQP port. Someone opened
http://broker:5672in a browser, or a monitoring/health check is doing an HTTP GET against 5672 instead of the management port 15672. - TLS client on the plaintext port. The application uses
amqps://or enabled TLS but connects to 5672 (plain) instead of 5671 (TLS), so a TLS ClientHello lands on the AMQP listener. - Plaintext client on the TLS port. The mirror image: an
amqp://client hitting 5671 sends a bare AMQP header into a listener expecting a TLS handshake. - A load balancer or proxy health check configured as HTTP/HTTPS against the AMQP TCP port instead of a TCP-level check.
- Port scanners or service discovery probing 5672 with non-AMQP payloads.
- Wrong protocol entirely. A client library configured for MQTT, STOMP, or the management HTTP API pointed at the core AMQP port rather than that protocol’s own listener.
- A version mismatch where a client sends an unexpected AMQP protocol-version header the broker won’t accept.
Diagnostic Workflow
The log line already tells you the source IP and the offending bytes — start there. Pull the recent bad_header events and the peers generating them:
sudo grep "bad_header" /var/log/rabbitmq/rabbit@$(hostname -s).log | tail -n 20
Decode the header bytes to identify the wrong protocol:
<<"GET ...">>,<<"POST ...">>,<<"HEAD ...">>→ an HTTP client on the AMQP port.<<22,3,1,...>>(leading byte 22 /0x16) → a TLS ClientHello on a plaintext listener.- Anything else non-
AMQP→ some other protocol or a scanner.
Confirm which listeners the broker actually has and on which ports:
rabbitmq-diagnostics listeners
Interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Interface: [::], port: 5671, protocol: amqp/ssl, purpose: AMQP 0-9-1 and AMQP 1.0 over TLS
Interface: [::], port: 15672, protocol: http, purpose: HTTP API
Interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Reproduce the HTTP-on-AMQP case deliberately to confirm the mapping between a misdirected client and the log entry:
# This SHOULD fail and produce a {bad_header,<<"GET / HT">>} in the broker log
curl -s http://localhost:5672/ ; echo "exit=$?"
Trace the offending source back to a real client. Take the peer IP from the log line and find who owns it — a health-check target, an app host, or a scanner:
# List current connections and their peers to correlate with the bad_header source IP
rabbitmqctl list_connections peer_host peer_port protocol
Because the connection is closed before login, it won’t appear in list_connections once rejected; correlate by the source IP and the timing instead.
Example Root Cause Analysis
An SRE noticed the RabbitMQ log growing rapidly with {bad_header,<<"GET / HT">>} entries, several per second, all from one internal IP. No client was reporting failures, which was the puzzle — messaging worked fine.
Decoding the header made the protocol obvious: GET / HT is the start of an HTTP request, so something was speaking HTTP to the AMQP port. rabbitmq-diagnostics listeners confirmed 5672 was the plain AMQP listener and 15672 the HTTP management API. Tracing the source IP led to a newly-added load balancer whose health check for the RabbitMQ target group had been configured as an HTTP GET on port 5672 instead of a plain TCP check. Every probe interval, the LB opened a socket, sent GET / HTTP/1.1, and RabbitMQ correctly rejected it as a non-AMQP client.
The fix had nothing to do with the broker: the health check was changed to a TCP connect check on 5672 (or an HTTP check redirected to the /api/health/checks/... endpoint on 15672). The bad_header noise stopped immediately. The lesson is that bad_header almost never means RabbitMQ is broken — it means something is speaking the wrong language to the port, and the received bytes plus the source IP tell you exactly what and who.
Prevention Best Practices
- Match the URI scheme to the port. Use
amqp://host:5672for plaintext andamqps://host:5671for TLS; never pointamqpsat 5672 oramqpat 5671. - Configure health checks as TCP on the AMQP port, or as HTTP against the management API on 15672 — never HTTP against 5672.
- Use the right listener per protocol. MQTT, STOMP, and the HTTP API each have their own ports; don’t aim those clients at 5672.
- Standardize connection settings through a shared config or connection factory so individual services can’t drift onto the wrong port or scheme.
- Restrict who can reach 5672. Firewall/security-group rules that limit the AMQP port to real clients cut down scanner-driven
bad_headernoise. - Alert on
bad_headervolume, since a sudden spike usually means a newly-misconfigured probe or client rather than a broker fault — catching it early keeps logs clean.
Quick Command Reference
# Recent protocol-mismatch events and their source IPs
sudo grep "bad_header" /var/log/rabbitmq/rabbit@$(hostname -s).log | tail -n 20
# What listeners/ports does the broker actually expose?
rabbitmq-diagnostics listeners
# Reproduce the HTTP-on-AMQP case (expect a bad_header in the log)
curl -s http://localhost:5672/ ; echo "exit=$?"
# Correlate live peers with the offending source IP
rabbitmqctl list_connections peer_host peer_port protocol
# Decode leading bytes:
# "GET "/"POST" -> HTTP client on AMQP port
# 22,3,1,... -> TLS client on a plaintext port
Conclusion
A bad_header error is RabbitMQ telling you, precisely and early, that the thing connecting to the port isn’t speaking the protocol that port expects. The broker is almost always healthy; the fault is a misdirected client — an HTTP health check on 5672, a TLS amqps:// URI aimed at the plaintext port, or a scanner probing the socket. The received bytes in the log (GET, a leading 22 for TLS, or anything that isn’t AMQP) plus the peer IP identify both the wrong protocol and its source.
Resolve it by aligning the client to the correct listener — the right port for the right scheme, TCP health checks instead of HTTP on the AMQP port, and each protocol pointed at its own listener. Then keep the logs clean by restricting access to the AMQP port and alerting on bad_header spikes, which reliably signal a new misconfiguration. For more connection and TLS troubleshooting, see the RabbitMQ guides.
Fixed it? Get 500 RabbitMQ & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.