TCP services such as databases, message queues, SSH gateways, and custom daemons need HAProxy to forward byte streams without trying to parse HTTP headers. A listener that accidentally inherits HTTP mode can break non-HTTP traffic, while an unchecked backend pool can keep sending clients to a closed port.
TCP mode keeps the frontend and backend at Layer 4. The frontend binds the address and port clients use, the backend lists the service nodes, the balance directive chooses a destination for each connection, and a check argument on each server line removes a failed node from rotation when the TCP check cannot connect.
The example below uses roundrobin so repeated test connections visibly reach more than one backend. For long-lived database or queue sessions, leastconn may fit better because new clients go to the server with fewer active connections. Use the service's native client for final validation when nc cannot complete the protocol handshake.
Steps to configure HAProxy TCP load balancing:
- Confirm the listener port, backend server addresses, and protocol-specific client test before editing HAProxy.
- Back up the active HAProxy configuration file.
$ sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.before-tcp-lb
- Open the HAProxy configuration file.
$ sudoedit /etc/haproxy/haproxy.cfg
- Add a TCP frontend and backend for the service.
frontend tcp_service bind *:5000 mode tcp timeout client 30s default_backend tcp_service_nodes backend tcp_service_nodes mode tcp balance roundrobin option tcp-check tcp-check connect timeout connect 5s timeout server 30s server tcp-a 10.0.10.11:5000 check server tcp-b 10.0.10.12:5000 checkReplace the listener port, backend IP addresses, and backend port with the real service values. Keep mode tcp in both sections when existing defaults use HTTP mode.
- Validate the complete HAProxy configuration before applying it.
$ sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg Configuration file is valid
The -V flag prints the success line. On current Ubuntu packages, sudo haproxy -c -f /etc/haproxy/haproxy.cfg can exit successfully without output.
- Reload HAProxy after the configuration validates.
$ sudo systemctl reload haproxy
The packaged systemd unit on current Ubuntu systems validates the configured file before sending the reload signal, but running the manual check first keeps failures visible before the service action.
Related: How to reload HAProxy gracefully
- Open two client connections through the HAProxy listener.
$ nc -w 2 proxy.example.net 5000 backend=tcp-a $ nc -w 2 proxy.example.net 5000 backend=tcp-b
A banner or echo-style test service can show the backend name directly. For databases, queues, SSH, or TLS-wrapped TCP services, use the matching client command and confirm the response comes through the proxy address.
- Test a planned backend outage during a maintenance window.
Stop one backend service or block its service port, wait for the configured health check to mark it down, and confirm new client connections continue through the remaining backend.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.