Skip to content

Priority Queuing

RouterOS uses an 8-level priority system (1 = highest, 8 = lowest) to decide which queue is served first when the parent link or interface is congested. Priority applies in both Simple Queue and Queue Tree, but with important differences in how it interacts with HTB’s bandwidth guarantees.

Simple Queue processes entries in the order they appear in the queue list (top-down matching), but the priority parameter controls which queue entry is served first when the outgoing interface is congested.

# Mark VoIP traffic
/ip firewall mangle
add chain=forward protocol=udp dst-port=5060,10000-20000 \
action=mark-packet new-packet-mark=pm-voip passthrough=no
# Priority queues
/queue simple
add name=voip packet-mark=pm-voip max-limit=5M/5M priority=1
add name=default target=0.0.0.0/0 max-limit=100M/100M priority=8

VoIP packets (priority 1) are dequeued before general traffic (priority 8) whenever the interface is busy. This ensures voice quality even when the link is saturated with bulk downloads.

Note: In Simple Queue, priority only affects how queued packets compete for the interface — it does not provide bandwidth guarantees. To guarantee minimum rates, use Queue Tree with limit-at.

Queue Tree uses HTB, which separates concerns:

  • limit-at — guaranteed (committed) rate, always honored regardless of priority.
  • max-limit — ceiling; the queue can never exceed this rate.
  • priority — controls which child queue gets excess bandwidth first, above limit-at but below max-limit.

Priority only comes into play when there is contention for bandwidth above the guaranteed rates. When total demand exceeds the parent’s capacity, the high-priority queue reaches its max-limit before low-priority queues are allowed to grow.

parent max-limit=100M
├── VoIP limit-at=2M max-limit=10M priority=1
├── Video limit-at=20M max-limit=60M priority=3
└── Bulk limit-at=5M max-limit=100M priority=8

In this hierarchy:

  • All three classes are always given at least their limit-at (2M, 20M, 5M).
  • Remaining capacity (up to 73M) is allocated by priority — VoIP fills to 10M first, then Video to 60M, then Bulk takes the rest.
  • Under low load, Bulk may use up to 73M. As load increases, Bulk is squeezed first.

Priority is only meaningful between sibling queues (children of the same parent). Priority has no effect on queues under different parents, and a child queue cannot out-prioritize its own parent.

A common real-world pattern: classify traffic into interactive, streaming, and bulk tiers.

/ip firewall mangle
# Interactive: VoIP + gaming + DNS
add chain=forward protocol=udp dst-port=5060,10000-20000 \
action=mark-packet new-packet-mark=pm-interactive passthrough=no \
comment="VoIP"
add chain=forward protocol=udp dst-port=27015-27030 \
action=mark-packet new-packet-mark=pm-interactive passthrough=no \
comment="Gaming"
add chain=forward protocol=udp dst-port=53 \
action=mark-packet new-packet-mark=pm-interactive passthrough=no \
comment="DNS"
# Streaming: HTTP/HTTPS
add chain=forward protocol=tcp dst-port=80,443 \
action=mark-packet new-packet-mark=pm-streaming passthrough=no \
comment="Web + streaming"
# Bulk: everything else
add chain=forward \
action=mark-packet new-packet-mark=pm-bulk passthrough=no \
comment="Bulk fallback"
# Parent on WAN interface (100 Mbps uplink)
/queue tree
add name=WAN-out parent=ether1-wan max-limit=100M
# Interactive — guaranteed 5M, can use up to 20M, first in line
add name=interactive parent=WAN-out packet-mark=pm-interactive \
limit-at=5M max-limit=20M priority=1
# Streaming — guaranteed 20M, can use up to 80M
add name=streaming parent=WAN-out packet-mark=pm-streaming \
limit-at=20M max-limit=80M priority=3
# Bulk — guaranteed 1M, takes whatever is left
add name=bulk parent=WAN-out packet-mark=pm-bulk \
limit-at=1M max-limit=100M priority=8

Under this configuration:

  • A VoIP call always gets at least 5 Mbps even when a large file transfer is in progress.
  • Streaming gets smooth bandwidth without competing with interactive traffic.
  • Bulk (backups, torrents) fills unused capacity but is the first to be squeezed.

Queue Tree is unidirectional. To shape both upload and download, create separate trees for ingress (use global-in or a bridge interface) and egress.

# Upload (egress on WAN)
/queue tree
add name=WAN-upload parent=ether1-wan max-limit=20M
add name=ul-voip parent=WAN-upload packet-mark=pm-interactive \
limit-at=2M max-limit=5M priority=1
add name=ul-streaming parent=WAN-upload packet-mark=pm-streaming \
limit-at=5M max-limit=18M priority=3
add name=ul-bulk parent=WAN-upload packet-mark=pm-bulk \
limit-at=1M max-limit=20M priority=8
# Download (ingress — use global-in or apply on LAN egress)
/queue tree
add name=WAN-download parent=global-in max-limit=100M
add name=dl-voip parent=WAN-download packet-mark=pm-interactive \
limit-at=2M max-limit=10M priority=1
add name=dl-streaming parent=WAN-download packet-mark=pm-streaming \
limit-at=20M max-limit=80M priority=3
add name=dl-bulk parent=WAN-download packet-mark=pm-bulk \
limit-at=5M max-limit=100M priority=8
/queue tree print stats

Watch rate (current throughput), queued-packets, and dropped for each class. Persistent drops on the interactive class indicate the guaranteed rate (limit-at) is too low.

Priority has no effect

  • Confirm queues are sibling nodes under the same parent.
  • Check that packet marks match — a queue with no traffic never competes.
  • Verify that the parent queue is actually congested. Priority has no visible effect on an uncongested link.

VoIP still has packet loss despite priority=1

  • Set a non-zero limit-at to guarantee bandwidth, not just ordering.
  • Check that mangle marks are applied on the correct chain and interface.
  • Use /queue tree print stats to confirm packets are actually hitting the VoIP queue.

Queues exceed max-limit

  • Another queue may be offloaded (FastTrack). Disable FastTrack for marked connections:
    /ip firewall mangle
    add chain=forward action=mark-connection new-connection-mark=no-track passthrough=yes
    /ip firewall filter
    add chain=forward connection-mark=no-track action=accept