Stop one guest's Netflix from killing the PMS connection. Simple Queue for quick caps, Queue Tree for VLAN-aware priority, PCQ for fair per-client sharing, and DSCP marking that survives across the whole path.
In a hotel or villa with a shared internet connection, quality of service is not optional — it's the difference between a 5-star review and a 1-star complaint about WiFi. Without QoS, a single guest running a 4K stream will saturate the uplink and make the property management system unresponsive, VoIP calls choppy, and every other guest unhappy. RouterOS gives you the tools to prevent this: Simple Queue for quick per-client caps, Queue Tree for VLAN-aware hierarchical shaping, and PCQ for automatic fair-share distribution without having to touch a rule for every new device.
We build this in three layers. Start with Simple Queue — fast to deploy, sufficient for small properties. Then upgrade to Queue Tree with VLAN-based priority. Finally add DSCP marking so traffic classification survives across switches and APs, and PCQ so the guest pool divides itself automatically no matter how many clients connect.
01
QoS in RouterOS is a pipeline: mark traffic in mangle, shape it in queues. You can't skip the marking step and expect queues to know which traffic is which.
RouterOS QoS works in two stages that must work together:
Stage 1 — Classification (Mangle): packets are inspected and marked in the prerouting or forward chain. Marks identify which VLAN, which service, or which priority class a packet belongs to. Without marks, queues can only act on everything equally.
Stage 2 — Shaping (Queues): marked packets enter a queue structure that enforces rate limits, priorities, and fair-share rules. Simple Queue works on source/destination addresses. Queue Tree works on interface traffic and packet marks from mangle.
The key insight: queues don't identify traffic, mangle does. A queue rule that matches src-address=192.168.30.0/24 works but doesn't scale — you'd need to update it every time the subnet changes. The correct pattern is: mangle marks packets from VLAN 30 with packet-mark=guest-traffic, and the queue matches on that mark. The mark is the contract between mangle and the queue.
In RouterOS, upload (LAN → WAN) is shaped on the outgoing WAN interface. Download (WAN → LAN) is shaped on the outgoing LAN interface — or with Simple Queue on the dst-address. Getting the interface direction wrong is the most common reason a queue appears configured but has no effect. Always verify with /queue print stats that the byte counters are incrementing.
02
The fastest path to "no single guest can hog the connection." Two fields, one rule per target. Start here.
Simple Queue is the easiest QoS tool in RouterOS. It matches on source or destination address, applies a max-limit for upload and download, and optionally bursts above the limit for short transfers. No mangle required. Ideal for small properties (up to ~20 clients) or as a quick fix while you build the full Queue Tree.
# Total guest pool: 50 Mbps down / 20 Mbps up # All guests share this pool — one queue for the whole subnet [admin@MikroTik] > /queue simple add \ name="guest-pool" \ target=192.168.30.0/24 \ max-limit=50M/20M \ comment="Guest WiFi VLAN 30 — total pool" # max-limit=download/upload (note: download first, then upload) # 50M/20M = 50 Mbps download, 20 Mbps upload ceiling for ALL guests combined.
Add individual guest caps so one device can't monopolise the pool. Burst allows full speed for a short duration (good for page loads) then throttles to the sustained rate.
# Per-guest cap: 10 Mbps down / 5 Mbps up sustained # Burst: 20 Mbps for the first 10 seconds (makes pages feel fast) [admin@MikroTik] > /queue simple add \ name="guest-per-client" \ target=192.168.30.0/24 \ max-limit=10M/5M \ burst-limit=20M/10M \ burst-threshold=8M/4M \ burst-time=10s/10s \ queue=pcq-download-default/pcq-upload-default \ comment="Guest per-client PCQ cap" # burst-limit: max speed during burst # burst-threshold: once sustained rate exceeds this, burst stops # burst-time: burst window in seconds # queue=pcq-*: use PCQ for fair per-IP sharing within the rule # Verify queue is active and counting bytes: [admin@MikroTik] > /queue simple print stats NAME RATE PACKET-RATE QUEUED-BYTES DROPPED guest-pool 12.4 Mbps 1823 0 B 0 guest-per-client 1.2 Mbps 183 0 B 0 # RATE shows current throughput. DROPPED > 0 means shaping is active. # If RATE = 0 and you expect traffic: check interface direction.
pcq-download-default / pcq-upload-default activates PCQ fair-sharing within this rule automatically.RouterOS Simple Queues are processed top-to-bottom, first match wins — exactly like firewall rules. If you have a per-client queue (target = 192.168.30.5) and a pool queue (target = 192.168.30.0/24), the per-client rule must appear before the pool rule. A more-specific address match must always be above a less-specific one. Check order with /queue simple print and use place-before= when adding.
03
Before Queue Tree can prioritise by VLAN, mangle must mark each packet. This is the classification layer that makes everything else work.
Mangle runs in the prerouting chain and marks packets before they enter the queue. We create one packet-mark per traffic class. Queue Tree will match these marks and apply the correct rate limits and priorities.
[admin@MikroTik] > /ip firewall mangle # ── STAFF / MGMT — highest priority ────────────────────────────────────── [admin@MikroTik] /ip/firewall/mangle> add \ chain=prerouting \ in-interface=vlan10 \ action=mark-packet \ new-packet-mark=staff-traffic \ passthrough=no \ comment="Mark Staff VLAN 10 traffic" # ── GUEST — medium priority, PCQ fair-share ─────────────────────────────── [admin@MikroTik] /ip/firewall/mangle> add \ chain=prerouting \ in-interface=vlan30 \ action=mark-packet \ new-packet-mark=guest-traffic \ passthrough=no \ comment="Mark Guest VLAN 30 traffic" # ── IOT — lowest priority, hard cap ────────────────────────────────────── [admin@MikroTik] /ip/firewall/mangle> add \ chain=prerouting \ in-interface=vlan40 \ action=mark-packet \ new-packet-mark=iot-traffic \ passthrough=no \ comment="Mark IoT VLAN 40 traffic" # ── DSCP marking — set alongside packet-mark ───────────────────────────── # Staff gets DSCP EF (Expedited Forwarding = highest priority class) # Guest gets DSCP AF21 (medium assured forwarding) # IoT gets DSCP CS1 (lower than best-effort — "background") [admin@MikroTik] /ip/firewall/mangle> add \ chain=prerouting in-interface=vlan10 \ action=change-dscp new-dscp=46 \ passthrough=yes \ comment="DSCP EF (46) for Staff" [admin@MikroTik] /ip/firewall/mangle> add \ chain=prerouting in-interface=vlan30 \ action=change-dscp new-dscp=18 \ passthrough=yes \ comment="DSCP AF21 (18) for Guest" [admin@MikroTik] /ip/firewall/mangle> add \ chain=prerouting in-interface=vlan40 \ action=change-dscp new-dscp=8 \ passthrough=yes \ comment="DSCP CS1 (8) for IoT" # Verify marks are being applied (check byte counters after traffic flows): [admin@MikroTik] > /ip firewall mangle print stats # CHAIN ACTION BYTES PACKETS COMMENT 0 prerouting mark-packet 142.3 MiB 398241 Mark Staff VLAN 10 1 prerouting mark-packet 890.1 MiB 1204821 Mark Guest VLAN 30 2 prerouting mark-packet 12.4 MiB 84921 Mark IoT VLAN 40 # Zero bytes on a rule = no traffic from that VLAN or wrong interface name.
The mark-packet rules use passthrough=no — once a packet is marked, stop processing further mangle rules for it. This prevents a staff packet from accidentally also matching a guest rule. The change-dscp rules use passthrough=yes — the DSCP change is applied and the packet continues, because the mark-packet rule already ran first (or runs after, depending on order). If you set passthrough=no on the DSCP rule, the packet-mark from the previous rule won't have been applied yet. Keep mark-packet first, DSCP second, both referencing the same in-interface.
04
Queue Tree is hierarchical: a parent queue owns the total WAN bandwidth, child queues each claim a slice with a priority and a rate limit.
Queue Tree operates on interface traffic and matches packet marks set by mangle. The structure is always a parent with children. The parent defines the total pipe (your WAN uplink speed). Children define per-class limits and priorities. When the link is congested, higher-priority children get served first; lower-priority children only get bandwidth when higher ones don't need it.
PCQ (Per-Connection Queue) automatically divides a bandwidth pool equally among active clients. RouterOS ships with two default PCQ types (pcq-download-default and pcq-upload-default). For the guest queue we use these directly — each unique destination IP (download) or source IP (upload) gets an equal share of the pool automatically.
# Check existing queue types — PCQ types should already exist [admin@MikroTik] > /queue type print 0 name="default" kind=fifo 1 name="ethernet-default" kind=pfifo 2 name="pcq-upload-default" kind=pcq classifier=src-address 3 name="pcq-download-default" kind=pcq classifier=dst-address # pcq-upload-default: divides upload bandwidth equally per source IP # pcq-download-default: divides download bandwidth equally per dest IP # classifier=src-address = split by who's sending (upload) # classifier=dst-address = split by who's receiving (download) # These defaults are sufficient. You can create custom ones if needed. # Optional: create a custom PCQ with rate-per-client limit [admin@MikroTik] > /queue type add \ name="pcq-guest-down" \ kind=pcq \ pcq-classifier=dst-address \ pcq-rate=10M \ pcq-burst-rate=20M \ pcq-burst-threshold=8M \ pcq-burst-time=10s # pcq-rate=10M: each individual client is capped at 10 Mbps download. # The pool queue (50M) and per-client cap (10M) work together: # 5 guests = 10M each = 50M total = pool saturated. # 3 guests = pool unused bandwidth distributed equally.
[admin@MikroTik] > /queue tree # ── PARENT: total WAN upload shaper ────────────────────────────────────── # Attach to WAN outgoing interface. All children inherit this ceiling. [admin@MikroTik] /queue/tree> add \ name="wan-shaper" \ parent=ether1 \ max-limit=100M \ comment="WAN upload shaper — 100 Mbps Starlink" # ── CHILD 1: Staff — priority 1, 40 Mbps ceiling ───────────────────────── [admin@MikroTik] /queue/tree> add \ name="staff-queue" \ parent=wan-shaper \ packet-mark=staff-traffic \ max-limit=40M \ priority=1 \ queue=default \ comment="Staff VLAN 10 — highest priority" # ── CHILD 2: Guest — priority 3, 50 Mbps, PCQ per-client ───────────────── [admin@MikroTik] /queue/tree> add \ name="guest-queue" \ parent=wan-shaper \ packet-mark=guest-traffic \ max-limit=50M \ priority=3 \ queue=pcq-guest-down \ comment="Guest VLAN 30 — PCQ fair-share per client" # ── CHILD 3: IoT — priority 8, 10 Mbps hard cap ───────────────────────── [admin@MikroTik] /queue/tree> add \ name="iot-queue" \ parent=wan-shaper \ packet-mark=iot-traffic \ max-limit=10M \ priority=8 \ queue=default \ comment="IoT VLAN 40 — background, hard cap" # Verify the tree structure: [admin@MikroTik] > /queue tree print NAME PARENT PACKET-MARK MAX-LIMIT PRIORITY wan-shaper ether1 — 100M 8 staff-queue wan-shaper staff-traffic 40M 1 guest-queue wan-shaper guest-traffic 50M 3 iot-queue wan-shaper iot-traffic 10M 8
wan-shaper owns the full 100 Mbps. Children match their mangle packet-mark and enforce their rate + priority. Under congestion, priority 1 (staff) is always served before priority 3 (guest) and priority 8 (IoT).Attaching the parent queue to parent=ether1 (WAN interface) only shapes traffic going out that interface — which is your upload. To shape download (WAN→LAN), you need a second parent queue attached to the LAN interface or bridge, or use the global queue parent. Many deployments only shape upload because that's the direction that gets congested first — but on Starlink where download is also contended, add a mirror tree on the LAN-facing interface.
Building a Queue Tree without mangle marks results in queues that match nothing — byte counters stay at zero, no shaping occurs. RouterOS will not warn you. The queues look correct in /queue tree print but silently do nothing because no packets carry the expected mark. Always verify mangle is working first (/ip firewall mangle print stats) before debugging Queue Tree. If mangle byte counters are zero, the problem is the mangle rules — fix those before touching the queue structure.
05
Packet marks disappear when a packet leaves the router. DSCP is written into the IP header itself — APs, switches, and the ISP can all read and act on it.
A RouterOS packet-mark only exists inside the router's memory — it's gone the moment the packet exits to the WAN or crosses to a downstream AP. DSCP (Differentiated Services Code Point) is a 6-bit field in the IP header that travels with the packet end-to-end. Set it once in mangle and every DSCP-aware device on the path can honour it.
The DSCP values used in this tutorial map to standard per-hop behaviours:
# DSCP value Class name Decimal Use case # ───────────────────────────────────────────────────────────────────────── # EF Expedited 46 VoIP, PMS, staff traffic — strict priority # Forwarding queued ahead of everything else # # AF21 Assured 18 Guest streaming — medium priority, # Forwarding 2,1 dropped before EF under congestion # # CS1 Class 8 IoT, background traffic — below # Selector 1 best-effort; dropped first under load # # BE Best Effort 0 Unmarked traffic — default treatment # Verify DSCP is being set (use torch to inspect live packets): [admin@MikroTik] > /tool torch interface=ether1 ip-protocol=any # Look for the DSCP column in torch output. # Or capture with /tool packet-sniffer and inspect headers.
06
Three commands tell you everything: queue stats show what's being shaped, torch shows live rates, and mangle stats confirm classification is working.
# Live queue stats — watch byte counts and dropped packets [admin@MikroTik] > /queue tree print stats interval=2 NAME RATE PACKET-RATE QUEUED-BYTES DROPPED COMMENT wan-shaper 88.2 Mbps 12048 0 B 0 staff-queue 12.1 Mbps 1820 0 B 0 Staff VLAN guest-queue 71.4 Mbps 9814 48.2 KiB 12483 Guest — shaping active iot-queue 4.7 Mbps 414 0 B 0 IoT # DROPPED > 0 on guest-queue = shaping is active, excess dropped. # DROPPED = 0 on all = either below limits or classification broken. # interval=2 refreshes every 2 seconds — Ctrl+C to stop. # Check mangle is classifying (bytes must be non-zero): [admin@MikroTik] > /ip firewall mangle print stats 0 prerouting mark-packet 142.3 MiB 398241 Mark Staff VLAN 10 1 prerouting mark-packet 890.1 MiB 1204821 Mark Guest VLAN 30 2 prerouting mark-packet 12.4 MiB 84921 Mark IoT VLAN 40 # Live per-IP breakdown inside a queue (who's using what): [admin@MikroTik] > /queue simple print stats # For PCQ queues, see per-flow breakdown: [admin@MikroTik] > /queue type print stats where name="pcq-guest-down" # See live traffic per IP on the guest VLAN: [admin@MikroTik] > /tool torch interface=vlan30 src-address=192.168.30.0/24 SRC-ADDRESS DST-ADDRESS PROTO TX RX 192.168.30.5 23.45.67.89 TCP 9.8 Mbps 1.2 Mbps ← near cap 192.168.30.12 203.0.113.50 TCP 9.9 Mbps 800 Kbps ← near cap 192.168.30.8 142.250.80.1 TCP 2.1 Mbps 200 Kbps # Torch shows real-time — exactly who is using what. Press Q to exit.
Start with the guest pool cap, add per-client PCQ, and you've solved 90% of complaints. The most common issue in hospitality WiFi is one device consuming the entire uplink — a guest torrent client, a phone with auto-backup, or a 4K stream. A 50M guest pool with 10M per-client PCQ cap means no single guest can take more than 10M even if the rest of the pool is idle. This alone eliminates the "someone's hogging the WiFi" complaint category.
Staff and PMS traffic should always be on a separate VLAN with priority 1. Even if a guest pool is being saturated, staff queues at priority 1 will preempt guest and IoT traffic. This means check-in terminals, payment processing, and the property management system always have bandwidth — even during full occupancy peak hours.
Monitor during peak hours, not at 03:00. QoS issues appear under load. Check /queue tree print stats interval=2 during dinner service (when guests are in rooms) or on a rainy afternoon. If guest DROPPED is non-zero and guest RATE equals max-limit, shaping is working. If staff-queue RATE is near its ceiling and guest-queue is also at max, you need a bigger WAN pipe — QoS cannot create bandwidth, only allocate what exists.
IoT hard cap protects the network from firmware updates and telemetry storms. IP cameras, smart thermostats, and access control systems sometimes push large firmware updates or cloud sync bursts at inopportune times. A 10 Mbps hard cap on the IoT VLAN ensures these background processes never affect guest or staff experience — and if an IoT device is compromised and starts flooding traffic, the cap limits the damage.
Takeaways
/queue tree print stats interval=2 under real load. DROPPED > 0 on the guest queue confirms shaping is active. Zero everywhere with traffic flowing means classification is broken — go back to mangle stats first.NOCTIS configures QoS for hospitality networks — VLAN-aware bandwidth allocation, PCQ guest fairness, and DSCP marking that works end-to-end across your APs. If your guests are complaining about WiFi speed while staff can't access the PMS, book a call to fix the root cause.
Book a Discovery Call →