Skip to content

Traffic Policer and Rate Limiting

RouterOS provides fine-grained traffic rate limiting through the combination of Firewall Mangle (classification) and Queue Tree (enforcement). This two-stage approach lets you identify specific traffic flows with packet marks, then apply bandwidth caps, guaranteed rates, burst allowances, and priorities through a hierarchical queue structure.

Traffic policing in RouterOS uses two subsystems working together:

  1. Firewall Mangle — classifies packets by assigning connection marks and packet marks. Mangle does not enforce any rate by itself; it only labels traffic for downstream processing.
  2. Queue Tree — enforces bandwidth policy. Queue Tree reads the packet marks assigned by Mangle and applies rate limits, priorities, and burst behavior.

This separation of classification from enforcement is the core RouterOS QoS design. You can reclassify traffic without touching your queue structure, and vice versa.

/ip firewall mangle
/queue tree
/queue type

Queue Tree (and Simple Queue) only processes packets that pass through the normal packet path. Traffic accelerated by the FastTrack connection tracker bypasses the queue subsystem entirely. If your QoS rules appear to have no effect, disable FastTrack for the affected connections or add a Mangle rule that prevents FastTrack from accelerating marked traffic.

# Exclude LAN traffic from FastTrack so QoS rules apply
/ip firewall filter
add chain=forward action=fasttrack-connection connection-state=established,related \
src-address=!192.168.88.0/24 dst-address=!192.168.88.0/24 comment="FastTrack WAN-to-WAN only"

Mangle rules assign symbolic labels to packets. The standard pattern is to mark the connection first, then mark packets belonging to that connection. This two-step approach ensures that reply packets (which have reversed src/dst) also receive the correct mark.

/ip firewall mangle
# Step 1: mark new connections matching the target traffic
add chain=forward connection-state=new src-address=192.168.88.0/24 \
action=mark-connection new-connection-mark=lan_up_conn passthrough=yes \
comment="Mark new LAN upload connections"
# Step 2: mark all packets belonging to those connections
add chain=forward connection-mark=lan_up_conn \
action=mark-packet new-packet-mark=lan_up_pkt passthrough=no \
comment="Mark LAN upload packets"

The passthrough parameter controls whether a packet continues matching subsequent Mangle rules after the current rule fires.

passthroughEffect
yesPacket continues to next rule. Use when further classification is needed.
noPacket stops matching Mangle rules after this rule. Use on the final packet-mark rule to avoid redundant processing.

Set passthrough=no on your final mark-packet rule to avoid re-processing packets that already have a mark.

Traffic typeChainDirection
Traffic passing through the routerforwardBoth
Traffic generated by the router itselfoutputOutbound only
Upload (LAN → WAN) classificationprerouting or forward
Download (WAN → LAN) classificationforward or postrouting

For most LAN/WAN rate-limiting scenarios, use the forward chain. Use prerouting only when you need to mark before routing decisions.

Queue Tree is a hierarchical bandwidth enforcement system based on HTB (Hierarchical Token Bucket). Each queue entry can set a guaranteed minimum rate (limit-at), a normal cap (max-limit), and optionally allow bursting above the cap.

ParameterDescription
parentParent queue or interface. Defines where in the hierarchy this queue sits.
packet-markThe Mangle packet mark this queue applies to.
limit-atGuaranteed minimum rate (CIR). Traffic up to this rate is always served.
max-limitNormal maximum rate. Traffic is capped at this rate under sustained load.
burst-limitPeak rate allowed during burst. Must be ≥ max-limit.
burst-thresholdAverage rate trigger. Burst is active while average rate stays below this value.
burst-timeAveraging window in seconds. Controls how quickly burst allowance is consumed.
priorityQueue priority (1=highest, 8=lowest). Higher-priority queues are served first.
queueQueue discipline type (e.g., default, a PCQ type).

Limit a specific host to 10 Mbps download and 5 Mbps upload:

/ip firewall mangle
# Mark download packets (WAN → host)
add chain=forward connection-state=new in-interface=ether1 dst-address=192.168.88.50 \
action=mark-connection new-connection-mark=host50_dl_conn passthrough=yes
add chain=forward connection-mark=host50_dl_conn \
action=mark-packet new-packet-mark=host50_dl passthrough=no
# Mark upload packets (host → WAN)
add chain=forward connection-state=new out-interface=ether1 src-address=192.168.88.50 \
action=mark-connection new-connection-mark=host50_ul_conn passthrough=yes
add chain=forward connection-mark=host50_ul_conn \
action=mark-packet new-packet-mark=host50_ul passthrough=no
/queue tree
# Download: cap at 10M, guarantee 2M
add name=host50-dl parent=global packet-mark=host50_dl \
limit-at=2M max-limit=10M priority=5
# Upload: cap at 5M, guarantee 1M
add name=host50-ul parent=global packet-mark=host50_ul \
limit-at=1M max-limit=5M priority=5

Burst allows traffic to temporarily exceed max-limit up to burst-limit. This is useful for web browsing and interactive traffic where short spikes feel faster to users, while the sustained average stays within policy.

RouterOS tracks a rolling average of the queue’s throughput over the burst-time window:

  1. If average-rate < burst-threshold → traffic may flow up to burst-limit
  2. If average-rate ≥ burst-threshold → rate is capped at max-limit
  3. When utilization drops, the average falls below burst-threshold again and burst re-activates

Setting burst-threshold=0 disables burst entirely.

Allow a 20 Mbps burst for up to ~8 seconds of a 16-second window before falling back to the 10 Mbps normal cap:

/queue tree
add name=host50-dl-burst parent=global packet-mark=host50_dl \
limit-at=2M \
max-limit=10M \
burst-limit=20M \
burst-threshold=8M \
burst-time=16s \
priority=5

Burst parameter guidelines:

  • burst-threshold should be set below max-limit (e.g., 80% of max-limit) for the burst to activate on idle-then-active flows
  • burst-time controls the averaging window; shorter windows (8–16s) allow more frequent short bursts; longer windows (30–60s) suit fewer but longer bursts
  • burst-limit should be set to the maximum your uplink can deliver to a single user

RouterOS provides three distinct mechanisms for handling excess traffic. Choosing the right one depends on your intent.

Use /ip firewall filter with action=drop to discard packets entirely. This is a security and policy tool, not a QoS tool. Use it to:

  • Block forbidden applications or protocols
  • Enforce hard access restrictions
  • Contain abuse or DDoS sources
/ip firewall filter
add chain=forward src-address=10.0.0.5 action=drop comment="Block abusive host"

Do not use drop for bandwidth shaping. Drop causes TCP retransmissions and poor user experience. When you want slower traffic rather than blocked traffic, use a queue.

Use Mangle action=change-dscp or action=set-priority to tag packets with a class-of-service label. The mark itself does not consume or delay any bandwidth — it is a signal to downstream systems.

Use marking to:

  • Signal QoS priority to upstream ISP or downstream devices
  • Differentiate traffic classes before applying Queue Tree priority queues
  • Tag VoIP or real-time traffic for preferential treatment
/ip firewall mangle
# Tag VoIP traffic with DSCP EF (Expedited Forwarding = 46)
add chain=forward protocol=udp dst-port=5060,10000-20000 \
action=change-dscp new-dscp=46 passthrough=yes comment="Mark VoIP DSCP EF"
# Set internal priority for VoIP (priority 1 = highest)
add chain=forward protocol=udp dst-port=5060,10000-20000 \
action=set-priority new-priority=1 passthrough=no

Throttle / Shape (Queue Tree or Simple Queue)

Section titled “Throttle / Shape (Queue Tree or Simple Queue)”

Throttling is the act of enforcing a rate limit. RouterOS throttles traffic by placing it in a queue and releasing it at the configured rate. Use Queue Tree (or Simple Queue) to:

  • Cap bandwidth for specific hosts, subnets, or traffic types
  • Guarantee minimum rates for critical services
  • Apply priority scheduling between traffic classes
# Prioritize VoIP over bulk traffic using Queue Tree
/queue tree
add name=voip parent=global packet-mark=voip_pkt priority=1 max-limit=2M
add name=bulk parent=global packet-mark=bulk_pkt priority=8 max-limit=50M
GoalToolAction
Block traffic entirelyFirewall Filteraction=drop
Signal class of serviceMangleaction=change-dscp / action=set-priority
Cap bandwidth / slow downQueue Tree or Simple Queuemax-limit, limit-at
Prioritize one flow over anotherQueue Treepriority (1=highest)

Per Connection Queue (PCQ) automatically creates dynamic sub-queues per classifier value (e.g., per source IP or destination IP). This provides fair bandwidth sharing across many clients without manually creating a queue entry for each IP address.

PCQ uses a single queue type that internally subdivides traffic by the configured classifier. Each substream gets up to pcq-rate bandwidth. If total offered load exceeds the parent max-limit, all active substreams are throttled proportionally.

ParameterDescription
pcq-classifierField used to distinguish substreams (src-address, dst-address, src-port, dst-port, or combinations)
pcq-rateMaximum rate per substream (per IP). Set to 0 for unlimited (fair-share only).
pcq-limitPer-substream packet buffer size
pcq-total-limitTotal packet buffer across all substreams

Limit each LAN client to 10 Mbps download and 5 Mbps upload, sharing a 100 Mbps / 50 Mbps link:

# Step 1: Define PCQ queue types
/queue type
add name=pcq-dl-10M kind=pcq pcq-classifier=dst-address pcq-rate=10M
add name=pcq-ul-5M kind=pcq pcq-classifier=src-address pcq-rate=5M
# Step 2: Mark download and upload packets in Mangle
/ip firewall mangle
# Download: WAN → LAN (destination is the LAN subnet)
add chain=forward in-interface=ether1 dst-address=192.168.88.0/24 \
action=mark-packet new-packet-mark=lan_dl passthrough=no \
comment="Mark download packets"
# Upload: LAN → WAN (source is the LAN subnet)
add chain=forward out-interface=ether1 src-address=192.168.88.0/24 \
action=mark-packet new-packet-mark=lan_ul passthrough=no \
comment="Mark upload packets"
# Step 3: Apply PCQ queues via Queue Tree
/queue tree
add name=LAN-Download parent=global packet-mark=lan_dl \
queue=pcq-dl-10M max-limit=100M comment="100M shared, 10M per IP"
add name=LAN-Upload parent=global packet-mark=lan_ul \
queue=pcq-ul-5M max-limit=50M comment="50M shared, 5M per IP"

With this configuration:

  • Each LAN client gets up to 10 Mbps download and 5 Mbps upload
  • If the link is under-utilized, clients can use up to their per-IP cap
  • The total shared pool is capped at 100 Mbps / 50 Mbps

Set pcq-rate=0 to remove the per-IP cap and allow PCQ to only enforce fairness — all active clients share the total bandwidth equally:

/queue type
add name=pcq-dl-fair kind=pcq pcq-classifier=dst-address pcq-rate=0
add name=pcq-ul-fair kind=pcq pcq-classifier=src-address pcq-rate=0
/queue tree
add name=LAN-Download-Fair parent=global packet-mark=lan_dl \
queue=pcq-dl-fair max-limit=100M
add name=LAN-Upload-Fair parent=global packet-mark=lan_ul \
queue=pcq-ul-fair max-limit=50M

Both tools enforce bandwidth, but they serve different use cases.

FeatureSimple QueueQueue Tree
Configuration effortLow — target by address/interface directlyHigher — requires Mangle marks
ScalabilitySequential scan; slower with many rulesHTB hierarchy; scales better
Hierarchical shapingLimitedFull parent/child class support
Per-IP via PCQSupportedSupported
Priority queuingLimitedFull priority scheduling
Typical use caseQuick per-host caps, small networksClass-based QoS, ISP deployments

Use Simple Queue for straightforward per-host or per-subnet limits in small deployments. Use Queue Tree when you need traffic class hierarchies, priority scheduling, or advanced burst/PCQ configurations.

The following example implements a three-class QoS policy on a 100 Mbps WAN link:

  • VoIP (UDP 5060 + RTP): priority 1, guaranteed 5 Mbps
  • Interactive (HTTPS, DNS, SSH): priority 3, up to 80 Mbps
  • Bulk (HTTP, file transfers): priority 8, up to 50 Mbps
# --- Mangle: classify traffic ---
/ip firewall mangle
# VoIP connections
add chain=forward connection-state=new protocol=udp dst-port=5060,10000-20000 \
action=mark-connection new-connection-mark=voip_conn passthrough=yes
add chain=forward connection-mark=voip_conn \
action=mark-packet new-packet-mark=voip_pkt passthrough=no
# Interactive (HTTPS, DNS, SSH)
add chain=forward connection-state=new protocol=tcp dst-port=443,22 \
action=mark-connection new-connection-mark=interactive_conn passthrough=yes
add chain=forward connection-state=new protocol=udp dst-port=53 \
action=mark-connection new-connection-mark=interactive_conn passthrough=yes
add chain=forward connection-mark=interactive_conn \
action=mark-packet new-packet-mark=interactive_pkt passthrough=no
# Bulk — everything else
add chain=forward connection-state=new \
action=mark-connection new-connection-mark=bulk_conn passthrough=yes
add chain=forward connection-mark=bulk_conn \
action=mark-packet new-packet-mark=bulk_pkt passthrough=no
# --- Queue Tree: enforce policy ---
/queue tree
# Root: total WAN cap
add name=WAN-Total parent=global max-limit=100M
# VoIP: guaranteed 5M, max 10M, priority 1
add name=VoIP parent=WAN-Total packet-mark=voip_pkt \
limit-at=5M max-limit=10M priority=1
# Interactive: up to 80M, priority 3
add name=Interactive parent=WAN-Total packet-mark=interactive_pkt \
max-limit=80M priority=3
# Bulk: up to 50M, priority 8 (gets leftover bandwidth)
add name=Bulk parent=WAN-Total packet-mark=bulk_pkt \
max-limit=50M priority=8

Queue rules have no effect

  • Verify FastTrack is not accelerating the affected connections. Check /ip firewall connection for the fasttrack flag.
  • Confirm the Mangle rules are matching: check counters with /ip firewall mangle print stats.
  • Ensure the packet-mark name in Queue Tree exactly matches the name in Mangle.

Burst not activating

  • Check that burst-threshold is set below max-limit (a common misconfiguration is setting threshold above max-limit, which means the burst condition is never met under normal load).
  • Verify burst-limit > max-limit.
  • Monitor the queue’s average rate with /queue tree monitor.

PCQ not limiting per IP

  • Confirm pcq-classifier matches the traffic direction (dst-address for download, src-address for upload).
  • Check that pcq-rate is non-zero if a per-IP cap is required.
  • Verify the Queue Tree entry references the correct PCQ type name.

Wrong traffic being marked

  • Add passthrough=no to final mark-packet rules to prevent packets from matching multiple mark rules.
  • Process more specific rules before general catch-all rules in the Mangle chain.
  • Use /ip firewall mangle print stats to confirm which rules are matching.