# How to Set Up frp with KCP Protocol for Better Performance on Lossy Networks

> Boost frp performance on lossy networks by enabling KCP protocol. Learn to configure frp server and client to use UDP transport for improved stability and speed.

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

---

**Enable KCP in frp by setting `kcpBindPort` on the server and `transport.protocol = "kcp"` on the client to replace TCP with a UDP-based transport that tolerates packet loss.**

The **fatedier/frp** (Fast Reverse Proxy) repository supports the **KCP protocol** as an alternative transport layer, allowing you to tunnel traffic over UDP with forward error correction. This configuration significantly reduces latency and improves throughput on unstable networks such as mobile or satellite connections. By switching from TCP to KCP, frp maintains its full feature set—including multiplexing and authentication—while gaining resilience against packet loss.

## Architecture and Implementation Details

frp implements KCP transport through a modular design that separates the underlying UDP socket handling from the high-level proxy logic.

### Server-Side KCP Listener

When you configure `kcpBindPort` in the server configuration, **frps** creates a dedicated UDP listener that accepts KCP connections. In [`server/service.go#L84-L89`](https://github.com/fatedier/frp/blob/dev/server/service.go#L84-L89), the server initializes `Service.kcpListener` and registers it with the generic connection handler, treating KCP sessions identically to TCP sockets once established.

### Client-Side Transport Selection

The client selects KCP through the `transport.protocol` configuration field. As defined in [`pkg/config/v1/client.go#L99-L104`](https://github.com/fatedier/frp/blob/dev/pkg/config/v1/client.go#L99-L104), the `ClientTransportConfig.Protocol` field accepts `"kcp"` as a valid value, triggering the client to dial the server using UDP-based KCP instead of standard TCP.

### Underlying KCP Implementation

frp leverages the third-party library `github.com/xtaci/kcp-go/v5` for the low-level transport. The session configuration in [`pkg/util/net/kcp.go#L96-L106`](https://github.com/fatedier/frp/blob/dev/pkg/util/net/kcp.go#L96-L106) applies production-ready defaults:

- **No-delay mode** (`SetNoDelay(1, 20, 2, 1)`) for fast retransmission
- **MTU 1350** to avoid fragmentation on most internet paths
- **Window size 1024×1024** to accommodate high-bandwidth delay products

The validation logic in [`pkg/config/v1/validation/visitor.go#L58-L59`](https://github.com/fatedier/frp/blob/dev/pkg/config/v1/validation/visitor.go#L58-L59) ensures that the KCP port is positive and the protocol name is supported before the client attempts to connect.

## Why KCP Improves Performance on Lossy Networks

KCP adds several mechanisms that TCP lacks, making it ideal for high-latency or lossy environments:

- **Forward error correction** recovers missing packets without waiting for a full round-trip retransmission.
- **Selective ACKs** allow the protocol to acknowledge specific received segments while requesting only the missing ones.
- **Configurable congestion control** via the window size parameter lets you tune the pipeline depth to match your specific network characteristics.

## Configuration Examples

### Server Configuration (frps.toml)

Configure the server to listen on both TCP and UDP ports. The `kcpBindPort` can match your standard `bindPort` since they use different protocols.

```toml

# frps.toml

bindPort = 7000          # TCP port for standard connections

kcpBindPort = 7000       # UDP port for KCP traffic

# Optional performance settings

transport.tcpMux = true
log.level = "info"

```

The `kcpBindPort` field maps directly to `ServerConfig.KCPBindPort` as defined in the configuration structs.

### Client Configuration (frpc.toml)

Set `transport.protocol` to `"kcp"` and ensure `serverPort` matches the server's `kcpBindPort`.

```toml

# frpc.toml

serverAddr = "your.frps.host"
serverPort = 7000          # Must align with server's kcpBindPort

transport.protocol = "kcp"

[[proxies]]
name = "ssh"
type = "tcp"
localPort = 22
remotePort = 6000

```

This configuration populates `ClientTransportConfig.Protocol` (see [[`pkg/config/v1/client.go`](https://github.com/fatedier/frp/blob/main/pkg/config/v1/client.go)](https://github.com/fatedier/frp/blob/dev/pkg/config/v1/client.go)), causing the client to establish a KCP session during initialization.

### Programmatic Configuration (Go)

For custom integrations using the frp client library:

```go
package main

import (
    "github.com/fatedier/frp/pkg/config/v1"
    "github.com/fatedier/frp/pkg/client"
)

func main() {
    cfg := &v1.ClientCommonConfig{
        ServerAddr: "your.frps.host",
        ServerPort: 7000,
        Transport: v1.ClientTransportConfig{
            Protocol: "kcp",  // Enable KCP transport
        },
    }
    
    cfg.Complete()  // Fill default values
    c, _ := client.NewClient(cfg)
    c.Run()
}

```

## Advanced Tuning Options

If the default settings do not match your network environment, you can modify the hardcoded parameters in [[`pkg/util/net/kcp.go`](https://github.com/fatedier/frp/blob/main/pkg/util/net/kcp.go)](https://github.com/fatedier/frp/blob/dev/pkg/util/net/kcp.go):

- **No-delay tuning**: Adjust `SetNoDelay(1, interval, resend, nc)` to control packet resend timing.
- **MTU adjustment**: Call `SetMtu(size)` with a larger value (up to 1400) if your network supports jumbo frames.
- **Window sizing**: Increase `SetWindowSize(snd, rcv)` beyond 1024 for high-bandwidth satellite links.

Note that these parameters require recompiling the binary; they are not exposed in the TOML configuration files in the current release.

## Summary

- **Enable KCP on the server** by setting `kcpBindPort` in [`frps.toml`](https://github.com/fatedier/frp/blob/main/frps.toml) to expose a UDP listener.
- **Configure the client** to use `transport.protocol = "kcp"` to establish UDP-based connections.
- **Benefit from loss tolerance** through forward error correction and selective acknowledgment built into the KCP protocol.
- **Reference implementation files** including [`server/service.go`](https://github.com/fatedier/frp/blob/main/server/service.go), [`pkg/util/net/kcp.go`](https://github.com/fatedier/frp/blob/main/pkg/util/net/kcp.go), and [`pkg/config/v1/client.go`](https://github.com/fatedier/frp/blob/main/pkg/config/v1/client.go) for the complete transport stack.
- **Tune performance** by modifying window sizes and no-delay parameters in the source code if default values are insufficient for your bandwidth-delay product.

## Frequently Asked Questions

### Does using KCP require opening additional firewall ports?

Yes. While TCP traffic uses `bindPort`, KCP operates over UDP. You must allow inbound UDP traffic on the `kcpBindPort` (default 7000) on your server firewall. The client only needs outbound UDP access to that same port.

### Can I mix TCP and KCP clients on the same frps server?

Absolutely. When you configure `kcpBindPort` alongside `bindPort`, the server accepts both TCP and KCP connections simultaneously. Individual clients choose their transport protocol via the `transport.protocol` setting without affecting other connected clients.

### Is KCP always faster than TCP?

Not necessarily. KCP excels on **lossy or high-latency networks** where TCP's congestion control would throttle throughput. On stable, low-latency networks (such as a data center LAN), TCP often performs better due to lower protocol overhead and kernel-level optimizations.

### How do I verify that my connection is using KCP?

Check the server logs after starting `frpc`. When KCP is active, the connection handshake occurs over UDP, and the logs will show the session establishing on the `kcpBindPort` rather than the standard TCP port. You can also monitor network traffic using `tcpdump` or Wireshark to confirm UDP packets on the configured port.