// DevOps

PCC on MikroTik: traffic balancing between two ISPs

Published on 2026-09-22

If a router has multiple external IP addresses or multiple links, all outgoing traffic still goes out via one of them by default. PCC (Per Connection Classifier) in RouterOS 7 distributes new connections between addresses: each connection goes entirely through one address, and different connections go through different ones. This is useful when your hosting provider applies traffic or speed limits per IP, and when you need to load all purchased addresses rather than just one.

About failover for internet access — see the article Redundancy of communication channels: Part 4 — Internet connectivity: BGP, DNS failover and CDN.


What PCC does and doesn’t do

PCC is a condition in firewall rules. It computes a hash from selected packet fields (addresses and ports) and divides connections into a specified number of streams. A marked connection keeps its mark until the end, so all its packets go through the same address.

What this gives you:

  • Total throughput increases when there are many connections. A single connection (one file download, one video call) will not become faster: it goes through one address. The win appears when there are many connections — for example, in an office or a group of servers.
  • Traffic is distributed among addresses. If the hosting provider limits volume or speed per IP, the load is split between them, and each address consumes its share of the limit.
  • All purchased addresses are used, not left idle.
  • PCC by itself does not provide failover. If one link stops working, connections that were assigned to its stream will be dropped until you remove it from load balancing. For automatic switching you need gateway availability checks — this is a separate setup.

In the example below PCC distributes connections between six external addresses using the both-addresses-and-ports classifier: the hash is computed from the source and destination addresses and ports, so the distribution is even. This variant has a downside: different connections from the same user to the same site may go out with different external addresses, and some services (banks, personal accounts) check that the client’s address does not change. If that matters, use both-addresses — then one client–server pair will always go through the same external address.


Configuring PCC on MikroTik RouterOS 7.x

Before starting, update the router to the latest version of RouterOS 7.

1. Add external IP addresses

All addresses are bound to the external interface. In the example this is wan-bridge; replace it with the name of your interface.

routeros
/ip address
add address=100.77.214.99/24 interface=wan-bridge network=100.77.214.0 comment="Main IP"
add address=100.77.214.97/24 interface=wan-bridge network=100.77.214.0
add address=100.77.214.109/24 interface=wan-bridge network=100.77.214.0
add address=100.77.214.110/24 interface=wan-bridge network=100.77.214.0
add address=100.77.214.111/24 interface=wan-bridge network=100.77.214.0
add address=100.77.214.112/24 interface=wan-bridge network=100.77.214.0

2. Set DNS servers

routeros
/ip dns
set servers="8.8.8.8, 1.1.1.1"

3. Create routing tables

Create a routing table for each external address: the router will send marked traffic according to these tables.

routeros
/routing table
add name=to_wan1 fib
add name=to_wan2 fib
add name=to_wan3 fib
add name=to_wan4 fib
add name=to_wan5 fib
add name=to_wan6 fib

4. Default route in each table

Specify the provider gateway in each table. In the example it is the same for all addresses — 100.77.214.1.

routeros
/ip route
add dst-address=0.0.0.0/0 gateway=100.77.214.1 routing-table=to_wan1
add dst-address=0.0.0.0/0 gateway=100.77.214.1 routing-table=to_wan2
add dst-address=0.0.0.0/0 gateway=100.77.214.1 routing-table=to_wan3
add dst-address=0.0.0.0/0 gateway=100.77.214.1 routing-table=to_wan4
add dst-address=0.0.0.0/0 gateway=100.77.214.1 routing-table=to_wan5
add dst-address=0.0.0.0/0 gateway=100.77.214.1 routing-table=to_wan6

5. Mark connections with PCC (Mangle)

The main step. Mangle rules mark new connections from the local network, and then the connection mark is used to assign a routing mark. In both-addresses-and-ports:6/X the number 6 is the number of streams (external addresses), X is the stream number from 0 to 5. No separate “stickiness” parameter is needed: the connection mark is kept until the connection ends, so all packets of one connection go through the same address. Replace lan-bridge with the name of your internal interface.

routeros
/ip firewall mangle
# Mark new connections from the local network
add chain=prerouting in-interface=lan-bridge connection-state=new action=mark-connection \
    new-connection-mark=wan1_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:6/0 \
    comment="PCC both-addr-ports WAN 1"

add chain=prerouting in-interface=lan-bridge connection-state=new action=mark-connection \
    new-connection-mark=wan2_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:6/1 \
    comment="PCC both-addr-ports WAN 2"

add chain=prerouting in-interface=lan-bridge connection-state=new action=mark-connection \
    new-connection-mark=wan3_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:6/2 \
    comment="PCC both-addr-ports WAN 3"

add chain=prerouting in-interface=lan-bridge connection-state=new action=mark-connection \
    new-connection-mark=wan4_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:6/3 \
    comment="PCC both-addr-ports WAN 4"

add chain=prerouting in-interface=lan-bridge connection-state=new action=mark-connection \
    new-connection-mark=wan5_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:6/4 \
    comment="PCC both-addr-ports WAN 5"

add chain=prerouting in-interface=lan-bridge connection-state=new action=mark-connection \
    new-connection-mark=wan6_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:6/5 \
    comment="PCC both-addr-ports WAN 6"

# Assign routing table by connection mark
add chain=prerouting connection-mark=wan1_conn action=mark-routing \
    new-routing-mark=to_wan1 passthrough=no comment="Route mark for WAN 1"

add chain=prerouting connection-mark=wan2_conn action=mark-routing \
    new-routing-mark=to_wan2 passthrough=no comment="Route mark for WAN 2"

add chain=prerouting connection-mark=wan3_conn action=mark-routing \
    new-routing-mark=to_wan3 passthrough=no comment="Route mark for WAN 3"

add chain=prerouting connection-mark=wan4_conn action=mark-routing \
    new-routing-mark=to_wan4 passthrough=no comment="Route mark for WAN 4"

add chain=prerouting connection-mark=wan5_conn action=mark-routing \
    new-routing-mark=to_wan5 passthrough=no comment="Route mark for WAN 5"

add chain=prerouting connection-mark=wan6_conn action=mark-routing \
    new-routing-mark=to_wan6 passthrough=no comment="Route mark for WAN 6"

# The same for traffic generated by the router itself
add chain=output connection-mark=wan1_conn action=mark-routing \
    new-routing-mark=to_wan1 passthrough=no comment="Output route mark for WAN 1"

add chain=output connection-mark=wan2_conn action=mark-routing \
    new-routing-mark=to_wan2 passthrough=no comment="Output route mark for WAN 2"

add chain=output connection-mark=wan3_conn action=mark-routing \
    new-routing-mark=to_wan3 passthrough=no comment="Output route mark for WAN 3"

add chain=output connection-mark=wan4_conn action=mark-routing \
    new-routing-mark=to_wan4 passthrough=no comment="Output route mark for WAN 4"

add chain=output connection-mark=wan5_conn action=mark-routing \
    new-routing-mark=to_wan5 passthrough=no comment="Output route mark for WAN 5"

add chain=output connection-mark=wan6_conn action=mark-routing \
    new-routing-mark=to_wan6 passthrough=no comment="Output route mark for WAN 6"

6. Firewall rules

These rules accept packets of already established connections and drop packets that do not belong to any known connection. This protects against failures during asymmetric routing when the request goes out through one address and the reply comes to another.

routeros
/ip firewall filter
add chain=forward connection-state=established,related action=accept comment="Accept established connections"
add chain=forward connection-state=invalid action=drop comment="Drop invalid connections"

7. NAT for each address

Each marked connection is translated to its external address. Without this, replies will return to the wrong address and connections will fail.

routeros
/ip firewall nat
add action=src-nat chain=srcnat routing-mark=to_wan1 to-addresses=100.77.214.99 out-interface=wan-bridge comment="NAT for WAN 1"
add action=src-nat chain=srcnat routing-mark=to_wan2 to-addresses=100.77.214.97 out-interface=wan-bridge comment="NAT for WAN 2"
add action=src-nat chain=srcnat routing-mark=to_wan3 to-addresses=100.77.214.109 out-interface=wan-bridge comment="NAT for WAN 3"
add action=src-nat chain=srcnat routing-mark=to_wan4 to-addresses=100.77.214.110 out-interface=wan-bridge comment="NAT for WAN 4"
add action=src-nat chain=srcnat routing-mark=to_wan5 to-addresses=100.77.214.111 out-interface=wan-bridge comment="NAT for WAN 5"
add action=src-nat chain=srcnat routing-mark=to_wan6 to-addresses=100.77.214.112 out-interface=wan-bridge comment="NAT for WAN 6"

# Fallback rule: connections without a PCC mark go through the main address
add action=masquerade chain=srcnat out-interface=wan-bridge comment="Default NAT for unmarked connections"

Important: the masquerade rule must be the last among NAT rules so it only matches traffic that PCC did not distribute.

8. Connection tracking timeouts

For long-lived connections it is useful to increase timeouts:

routeros
/ip firewall connection tracking
set generic-timeout=10m tcp-established-timeout=1d tcp-fin-wait-timeout=30s tcp-close-wait-timeout=30s

Checking the distribution

You can view statistics in WinBox or WebFig. For a rough estimate of speed on the external interface a simple script will do:

routeros
/system script
add name="check-load-balance" source={
    :local wan1traffic [/interface get wan-bridge value-name=tx-byte]
    :put "WAN Traffic: $wan1traffic"
    :delay 3s
    :local wan1traffic2 [/interface get wan-bridge value-name=tx-byte]
    :put "WAN Traffic after 3s: [($wan1traffic2 - $wan1traffic) * 8 / 3 / 1000] kbit/s"
}

The script shows the total speed through the external interface. To see the distribution by address, open the Connections table in the Firewall section and filter it by the connection marks wan1_conn…wan6_conn.


Conclusion

PCC lets you use all the router’s external addresses and distribute load between them, including to avoid exceeding traffic limits on a single IP. It does not speed up a single connection and does not replace failover configuration. After setup, check the distribution in the connections table and monitor the network for a few days before considering the scheme operational.

// Reviews

Related reviews

ladohinpy

MikroTik hAP router setup. I'll set up a MikroTik Wi‑Fi router for you.

2025-07-21 · ★ 5/5

An excellent specialist, a savvy expert, and a wonderful person. In an hour he fixed what we'd been racking our brains over for days! I'm sure this won't be the last time we rely on his boundless professionalism.

An excellent specialist, a savvy expert, and a wonderful person. In an hour he fixed for us what we had been scratching our heads over for days! I'm sure this won't be the first time we make use of his boundless …

Ravenor

MikroTik hAP router setup. I'll configure a MikroTik Wi-Fi router for you.

2025-05-28 · ★ 5/5

// Contact

Need help?

Get in touch with me and I'll help solve the problem

I reply within one business day (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirm that you are not a bot.

Write and get a quick reply