# How frp TCP Stream Multiplexing Improves Performance and Reduces Latency

> Discover how frp TCP stream multiplexing boosts performance and slashes latency by consolidating multiple proxy streams on one connection and reusing established sockets. Learn more!

- Repository: [fatedier/frp](https://github.com/fatedier/frp)
- Tags: performance
- Published: 2026-02-26

---

**frp uses the Yamux library to multiplex multiple logical proxy streams over a single TCP connection, eliminating per-request handshake overhead and reducing latency by reusing an established congestion-controlled socket.**

frp (Fast Reverse Proxy) is an open-source reverse proxy application that enables exposing local servers behind NATs to the internet. One of its key performance optimizations is **frp TCP stream multiplexing**, which allows multiple proxy connections to share a single underlying TCP socket between the client (`frpc`) and server (`frps`).

## What Is frp TCP Stream Multiplexing?

TCP stream multiplexing in frp is implemented via the **TCPMux** feature, which leverages the Yamux library to create many logical streams over one physical TCP connection. Instead of opening a new TCP socket for every proxy request, frp maintains a persistent session and opens lightweight streams within it.

This approach eliminates the TCP three-way handshake and TLS negotiation for every new proxy connection, significantly reducing connection establishment time and CPU overhead.

## Performance Benefits of TCP Stream Multiplexing in frp

The following table summarizes how TCPMux improves performance and reduces latency:

| TCPMux Capability | Performance Impact |
|-------------------|-------------------|
| **Reuses one TCP socket** for all proxy connections | Eliminates TCP handshake and TLS setup per request, saving round-trip time and CPU cycles |
| **Maintains persistent connections** with configurable `TCPMuxKeepaliveInterval` | Prevents idle timeouts, allowing subsequent streams to start instantly without connection setup |
| **Shares congestion-control state** (window size, RTT, loss recovery) across streams | Improves throughput for many small streams by leveraging an already-trained congestion window |
| **Aggregates traffic** on a single port via `TCPMuxHTTPConnectPort` | Reduces kernel socket overhead and simplifies NAT/firewall configuration |
| **Enables per-proxy routing** via the TCPMux group controller | Allows multiple domains or users to share one multiplexed connection while remaining logically isolated |

## How frp Implements TCP Stream Multiplexing

frp's multiplexing architecture involves coordinated configuration on both client and server sides, utilizing the Yamux library for session management.

### Server-Side Configuration

In [`pkg/config/v1/server.go`](https://github.com/fatedier/frp/blob/main/pkg/config/v1/server.go), TCPMux is enabled by default with `TCPMux` set to `true`:

```go
// Server transport defaults to TCPMux enabled
// src: pkg/config/v1/server.go#L58-L64
c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true))

```

When `TCPMuxHTTPConnectPort` is configured, the server creates an HTTP CONNECT multiplexer listener in [`server/service.go`](https://github.com/fatedier/frp/blob/main/server/service.go):

```go
// Create the http-connect multiplexer if needed
// src: server/service.go#L185-L199
if cfg.TCPMuxHTTPConnectPort > 0 {
    address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.TCPMuxHTTPConnectPort))
    l, err = net.Listen("tcp", address)
    svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout)
}

```

### Client-Side Connection Handling

On the client side, [`client/connector.go`](https://github.com/fatedier/frp/blob/main/client/connector.go) establishes a single TCP connection and wraps it in a Yamux session when `tcpMux` is enabled:

```go
// Open the underlying connection and start a Yamux session
// src: client/connector.go#L15-L25
if !lo.FromPtr(c.cfg.Transport.TCPMux) { return nil }
conn, err := c.realConnect()
fmuxCfg := fmux.DefaultConfig()
fmuxCfg.KeepAliveInterval = time.Duration(c.cfg.Transport.TCPMuxKeepaliveInterval) * time.Second
session, err := fmux.Client(conn, fmuxCfg)   // one Yamux session
c.muxSession = session

```

Each proxy connection request then opens a new logical stream within this session:

```go
// Retrieve a stream from the Yamux session
// src: client/connector.go#L36-L42
stream, err := c.muxSession.OpenStream()

```

### Stream Routing and HTTP CONNECT

The server routes multiplexed streams using [`server/group/tcpmux.go`](https://github.com/fatedier/frp/blob/main/server/group/tcpmux.go) and [`server/proxy/tcpmux.go`](https://github.com/fatedier/frp/blob/main/server/proxy/tcpmux.go). For HTTP CONNECT proxying, [`pkg/util/tcpmux/httpconnect.go`](https://github.com/fatedier/frp/blob/main/pkg/util/tcpmux/httpconnect.go) parses the CONNECT request and routes accordingly:

```go
// Parse CONNECT request and produce a host-specific stream
// src: pkg/util/tcpmux/httpconnect.go#L49-L70
host, httpUser, httpPwd, err := muxer.readHTTPConnectRequest(rd)

```

## Configuring TCPMux in frp

### Server Configuration (frps)

Enable multiplexing and configure keep-alive intervals in [`frps.toml`](https://github.com/fatedier/frp/blob/main/frps.toml):

```yaml

# frps.toml

[common]

# Enable multiplexing (default = true)

tcp_mux = true
tcp_mux_keepalive_interval = 30   # seconds

tcp_mux_http_connect_port = 7001  # port for HTTP CONNECT multiplexing

tcp_mux_passthrough = false       # let frps handle CONNECT response

```

### Client Configuration (frpc)

Configure the client to use the multiplexed connection:

```yaml

# frpc.toml

[common]
server_addr = "your.frps.host"
server_port = 7000
tcp_mux = true                     # use one underlying connection

tcp_mux_keepalive_interval = 30   # keep-alive for the Yamux session

```

### HTTP CONNECT Multiplexing

For HTTP CONNECT proxying, specify the multiplexer type in your proxy configuration:

```yaml
[ssh]
type = "tcp"
local_port = 2222
remote_port = 22
multiplexer = "httpconnect"   # tells frpc to use the HTTP CONNECT port

```

## Key Source Files for frp TCP Stream Multiplexing

| Path | Role |
|------|------|
| [`pkg/config/v1/server.go`](https://github.com/fatedier/frp/blob/main/pkg/config/v1/server.go) | Transport configuration with default `TCPMux = true` |
| [`client/connector.go`](https://github.com/fatedier/frp/blob/main/client/connector.go) | Opens Yamux session and manages stream creation |
| [`server/service.go`](https://github.com/fatedier/frp/blob/main/server/service.go) | Creates HTTP CONNECT multiplexer listener |
| [`server/group/tcpmux.go`](https://github.com/fatedier/frp/blob/main/server/group/tcpmux.go) | Routes multiplexed streams to correct proxy listeners |
| [`server/proxy/tcpmux.go`](https://github.com/fatedier/frp/blob/main/server/proxy/tcpmux.go) | Proxy factory for TCPMux type |
| [`pkg/util/tcpmux/httpconnect.go`](https://github.com/fatedier/frp/blob/main/pkg/util/tcpmux/httpconnect.go) | Implements HTTP CONNECT multiplexing logic |

## Summary

- **frp TCP stream multiplexing** collapses multiple logical proxy connections into a single physical TCP socket using the Yamux library.
- **Eliminates per-connection overhead** by removing TCP handshakes and TLS negotiations for each new proxy request.
- **Reduces latency** through persistent connections with configurable keep-alive intervals and shared congestion-control state.
- **Simplifies infrastructure** by aggregating traffic onto single ports and reducing kernel socket allocation.
- **Maintains isolation** between different proxies through logical stream routing while sharing the underlying transport.

## Frequently Asked Questions

### What is the difference between TCPMux and regular TCP proxying in frp?

Regular TCP proxying creates a new TCP connection for every proxy request, requiring a full TCP handshake and TLS negotiation each time. **TCPMux** maintains a single persistent TCP connection between frpc and frps, opening lightweight logical streams within that session for each new proxy request, which eliminates connection setup latency.

### How does TCPMux affect latency compared to creating new connections?

TCPMux significantly reduces latency by removing the TCP three-way handshake and TLS handshake from the critical path of new proxy requests. Once the initial Yamux session is established, new streams start instantly without waiting for network round-trips, and shared congestion-control state ensures optimal throughput immediately rather than requiring slow-start ramp-up.

### Can I use TCPMux with HTTP CONNECT proxying?

Yes, frp supports HTTP CONNECT multiplexing through the `tcp_mux_http_connect_port` configuration on the server and the `multiplexer = "httpconnect"` setting on the client. This allows the HTTP CONNECT protocol to benefit from the same connection reuse and reduced overhead as standard TCP multiplexing, with the server handling CONNECT request parsing in [`pkg/util/tcpmux/httpconnect.go`](https://github.com/fatedier/frp/blob/main/pkg/util/tcpmux/httpconnect.go).

### What happens if the multiplexed connection drops?

If the underlying TCP connection carrying the Yamux session is interrupted, all logical streams within that session are terminated simultaneously. The frp client will automatically attempt to reconnect and establish a new Yamux session based on the configured keep-alive intervals and retry logic, but any in-flight requests on the dropped connection will need to be reestablished on the new session.