Skip to content
MikroTik RouterOS Docs

Queue Tree

For the impatient: basic traffic prioritization setup.

Step 1: Create packet marks in mangle

/ip/firewall/mangle/add chain=forward protocol=udp dst-port=5060-5061 \
action=mark-packet new-packet-mark=voip passthrough=no

Step 2: Create queue tree

/queue/tree/add name=total parent=global max-limit=100M
/queue/tree/add name=voip-queue parent=total packet-mark=voip priority=1 max-limit=10M
/queue/tree/add name=other parent=total packet-mark=no-mark priority=8 max-limit=90M

Verify with:

/queue/tree/print stats

What this does: Queue Tree implements hierarchical traffic shaping using HTB (Hierarchical Token Bucket) for advanced QoS. It creates unidirectional queues attached to HTB trees, allowing traffic prioritization, bandwidth allocation, and guaranteed minimum rates.

When to use this:

  • Prioritizing VoIP/gaming over bulk downloads
  • Implementing global QoS policies
  • Fair bandwidth distribution with PCQ
  • Per-interface bandwidth control
  • Scenarios requiring hierarchical bandwidth allocation

Prerequisites:

  • Packet marks from /ip/firewall/mangle
  • FastTrack disabled (or excluded for queued traffic)
  • Understanding of HTB parent/child relationships

FastTrack Conflict

FastTrack bypasses mangle and queue processing. You must disable FastTrack or exclude traffic from FastTrack before it can be queued.

AspectSimple QueueQueue Tree
DirectionBidirectional (one entry)Unidirectional
Marking requiredNo (uses target IP)Yes (packet marks)
ProcessingSequential (ordered)Parallel (non-ordered)
ConfigurationSimplerMore complex
CPU usageMulti-coreSingle core
Use casePer-client limitsGlobal QoS, prioritization

Use Queue Tree when: You need traffic prioritization, hierarchical QoS, or per-interface control.

Use Simple Queues when: You just need per-IP bandwidth limits.

FastTrack bypasses queue processing. Disable it:

/ip/firewall/filter/disable [find action=fasttrack-connection]

Or exclude specific traffic before FastTrack:

/ip/firewall/filter/add chain=forward src-address=192.168.1.0/24 action=accept \
place-before=[find action=fasttrack-connection]

Clear existing FastTracked connections:

/ip/firewall/connection/remove [find fasttrack=yes]

Queue Tree requires packet marks. Mark traffic in mangle:

# Mark VoIP traffic
/ip/firewall/mangle/add chain=forward protocol=udp dst-port=5060-5061 \
action=mark-packet new-packet-mark=voip passthrough=no comment="VoIP SIP"
/ip/firewall/mangle/add chain=forward protocol=udp dst-port=10000-20000 \
action=mark-packet new-packet-mark=voip passthrough=no comment="VoIP RTP"
# Mark bulk downloads (large connections)
/ip/firewall/mangle/add chain=forward protocol=tcp dst-port=80,443 \
connection-bytes=500000-0 action=mark-packet new-packet-mark=bulk \
passthrough=no comment="Large HTTP connections"

Create the top-level queue with total bandwidth:

/queue/tree/add name=total-bandwidth parent=global max-limit=100M

Add prioritized child queues:

# High priority: VoIP (guaranteed 2M, max 10M, priority 1)
/queue/tree/add name=voip parent=total-bandwidth packet-mark=voip \
limit-at=2M max-limit=10M priority=1
# Low priority: Bulk (guaranteed 10M, max 80M, priority 8)
/queue/tree/add name=bulk parent=total-bandwidth packet-mark=bulk \
limit-at=10M max-limit=80M priority=8
# Catch-all: Unmarked traffic
/queue/tree/add name=other parent=total-bandwidth packet-mark=no-mark \
limit-at=20M max-limit=80M priority=4

Check mangle is marking packets:

/ip/firewall/mangle/print stats where new-packet-mark!=

Check queue tree is processing traffic:

/queue/tree/print stats

Equal bandwidth per user automatically:

Step 1: Create PCQ queue types

/queue/type/add name=pcq-download kind=pcq pcq-rate=10M pcq-classifier=dst-address
/queue/type/add name=pcq-upload kind=pcq pcq-rate=5M pcq-classifier=src-address

Step 2: Mark traffic by direction

/ip/firewall/mangle/add chain=forward in-interface=ether1-WAN \
action=mark-packet new-packet-mark=download passthrough=no
/ip/firewall/mangle/add chain=forward out-interface=ether1-WAN \
action=mark-packet new-packet-mark=upload passthrough=no

Step 3: Create queue trees with PCQ

/queue/tree/add name=client-download parent=global packet-mark=download \
queue=pcq-download max-limit=100M
/queue/tree/add name=client-upload parent=global packet-mark=upload \
queue=pcq-upload max-limit=50M

Limit bandwidth on a specific interface:

# Mark traffic going to LAN
/ip/firewall/mangle/add chain=forward out-interface=ether2-LAN \
action=mark-packet new-packet-mark=to-lan passthrough=no
# Create queue on interface
/queue/tree/add name=lan-limit parent=ether2-LAN packet-mark=to-lan max-limit=50M

Allow temporary speed boost for interactive traffic:

/queue/tree/add name=interactive parent=global packet-mark=interactive \
max-limit=10M limit-at=2M \
burst-limit=50M burst-threshold=5M burst-time=16s \
priority=2

This provides:

  • Guaranteed 2 Mbps (limit-at)
  • Normal maximum 10 Mbps (max-limit)
  • Burst to 50 Mbps when average < 5 Mbps over 16 seconds
  • Maximum burst duration: 5M × 16s / 50M = 1.6 seconds

Prioritize gaming traffic:

# Mark gaming ports
/ip/firewall/mangle/add chain=forward protocol=udp dst-port=3074,3478-3480 \
action=mark-packet new-packet-mark=gaming passthrough=no comment="Xbox/PlayStation"
# High priority queue
/queue/tree/add name=gaming parent=total-bandwidth packet-mark=gaming \
limit-at=5M max-limit=20M priority=1

For stateful marking (more efficient):

# Mark connection first
/ip/firewall/mangle/add chain=forward connection-state=new protocol=tcp dst-port=80,443 \
action=mark-connection new-connection-mark=http-conn passthrough=yes
# Then mark packets based on connection
/ip/firewall/mangle/add chain=forward connection-mark=http-conn \
action=mark-packet new-packet-mark=http-pkt passthrough=no

Use DSCP markings from upstream devices:

# Mark based on DSCP
/ip/firewall/mangle/add chain=forward dscp=46 \
action=mark-packet new-packet-mark=ef-traffic passthrough=no comment="DSCP EF"
# Priority queue for EF traffic
/queue/tree/add name=expedited parent=global packet-mark=ef-traffic priority=1 max-limit=10M
ParentDescription
globalGlobal HTB tree (affects all traffic)
global-inIngress global tree
global-outEgress global tree
<interface>Interface-specific tree (e.g., ether1)
<queue-name>Another queue tree (hierarchical)
  • limit-at: Guaranteed minimum bandwidth (CIR)
  • max-limit: Maximum bandwidth ceiling (MIR)
  • priority: Distributes bandwidth above limit-at values

Priority only matters when there’s excess bandwidth. Lower number = higher priority.

ParameterDescription
burst-limitMaximum rate during burst
burst-thresholdAverage rate below which burst activates
burst-timeWindow for calculating average rate

Formula: max-burst-duration = burst-threshold × burst-time / burst-limit

Confirm Queue Tree is working:

/ip/firewall/mangle/print stats where new-packet-mark!=

Expected: Non-zero bytes/packets for active rules.

/queue/tree/print stats

Expected: Non-zero rate/bytes for active queues.

/ip/firewall/filter/print where action=fasttrack-connection

Expected: Disabled, or traffic excluded before it.

/ip/firewall/connection/print where fasttrack=yes

Expected: Empty if FastTrack properly disabled.

/queue/tree/print stats where dropped>0

High dropped count indicates queue overflow.

SymptomCauseSolution
Queue shows zero trafficFastTrack bypassingDisable FastTrack; clear fasttracked connections
Mangle shows hits but queue emptyUsing connection mark not packet markCreate packet mark from connection mark
Unmarked traffic exceeds limitsMissing no-mark queueAdd packet-mark=no-mark catch-all queue
Priority not workingSum of limit-at exceeds parentEnsure sum of children limit-at ≤ parent max-limit
Upload works, download doesn’tWrong parent for traffic directionUse appropriate parent (global-in/out or interface)
Prerouting marks not workingv6+ packet flow changesUse forward or postrouting chain instead
Bridged traffic not queuedBridge firewall disabledEnable use-ip-firewall=yes on bridge
DNS slow after adding queueGlobal parent affects router trafficUse interface parent or exclude router traffic
Burst never activatesThreshold misconfiguredSet threshold between limit-at and max-limit
/ip/firewall/mangle/print stats

If mangle shows zero hits, traffic isn’t reaching those rules.

Verify child limit-at values don’t exceed parent:

/queue/tree/print where parent=total-bandwidth

Sum of limit-at should be ≤ parent’s max-limit.

Common Mistakes

  • Forgetting to disable FastTrack - Most common cause of queue tree not working
  • Using connection mark instead of packet mark - Queue tree requires packet marks
  • No catch-all queue - Unmarked traffic bypasses queue tree entirely
  • limit-at sum too high - Children’s guaranteed bandwidth can’t exceed parent’s maximum
  • Wrong chain for marking - Use forward/postrouting, not prerouting for incoming traffic
  • Global parent affecting DNS - Router’s own traffic queued; use interface parent
  • Firewall Basics - FastTrack conflicts with queues
  • Torch - monitor traffic for QoS tuning
  • SNMP - remote queue statistics
CommandDescription
/queue/tree/addCreate queue tree entry
/queue/tree/printView all entries
/queue/tree/print statsView statistics
/queue/tree/reset-countersReset byte/packet counters
/queue/type/addCreate queue type (PCQ, etc.)
PropertyTypeDefaultDescription
namestring-Unique identifier (required)
parentstring-HTB parent: global, interface, or queue name
packet-markstring-Packet mark from mangle
max-limitrate0Maximum bandwidth (MIR)
limit-atrate0Guaranteed minimum (CIR)
priority1-88Priority (1=highest)
queuestringdefaultQueue type
burst-limitrate0Maximum burst rate
burst-thresholdrate0Threshold for burst activation
burst-timetime0sAveraging window
PropertyDescription
rateCurrent data rate
packet-rateCurrent packet rate
bytesTotal bytes processed
packetsTotal packets processed
queued-bytesBytes in queue buffer
queued-packetsPackets in queue buffer
droppedPackets dropped (overflow)