Skip to content

ISP Subscriber Management

RouterOS is widely deployed as a broadband access concentrator (BRAS/BNG) for ISP subscriber delivery. The typical architecture uses:

  • PPPoE or DHCP for subscriber access
  • RADIUS for centralized authentication, authorization, and accounting (AAA)
  • IP pools for dynamic address assignment
  • Mikrotik-Rate-Limit VSA or PCQ queues for per-subscriber bandwidth enforcement

This guide covers the end-to-end configuration for both PPPoE and DHCP subscriber models.

Subscriber CPE
│ PPPoE / DHCP
RouterOS (BNG/BRAS)
├── /interface pppoe-server or /ip dhcp-server
├── /radius → AAA server
├── /ip pool (address pools)
└── /queue (bandwidth enforcement)
RADIUS Server (FreeRADIUS, Radiusd, etc.)
├── Authentication database
├── Returns: Framed-IP-Address / Framed-Pool
├── Returns: Mikrotik-Rate-Limit
└── Accounting: Start / Interim / Stop
/ip pool
add name=pppoe-standard ranges=100.64.0.2-100.64.0.254
add name=pppoe-premium ranges=100.64.1.2-100.64.1.254
add name=pppoe-business ranges=100.64.2.2-100.64.2.30

Profiles set defaults; RADIUS attributes override them per-subscriber:

/ppp profile
add name=isp-standard \
local-address=100.64.0.1 \
remote-address=pppoe-standard \
dns-server=8.8.8.8,8.8.4.4 \
use-compression=no \
use-encryption=no
add name=isp-premium \
local-address=100.64.1.1 \
remote-address=pppoe-premium \
dns-server=8.8.8.8,8.8.4.4
/radius
add address=10.10.0.5 \
secret=ISPSecret \
service=ppp \
authentication-port=1812 \
accounting-port=1813
/ppp aaa
set use-radius=yes \
accounting=yes \
interim-update=5m
/interface pppoe-server server
add interface=ether1 \
service-name=isp \
default-profile=isp-standard \
authentication=chap,mschap2 \
one-session-per-host=yes \
disabled=no

one-session-per-host=yes prevents MAC address spoofing from generating duplicate sessions.

/radius incoming
set accept=yes port=3799

For cable or fixed-line deployments using DHCP instead of PPPoE:

/ip pool
add name=dhcp-subscribers ranges=10.20.0.2-10.20.255.254
/ip dhcp-server
add name=subscriber-dhcp \
interface=bridge-subs \
address-pool=dhcp-subscribers \
use-radius=yes \
accounting=yes \
interim-update=5m \
lease-time=1d
/ip dhcp-server network
add address=10.20.0.0/16 \
gateway=10.20.0.1 \
dns-server=8.8.8.8
/radius
add address=10.10.0.5 \
secret=ISPSecret \
service=dhcp \
authentication-port=1812 \
accounting-port=1813
Section titled “Method 1 — Mikrotik-Rate-Limit VSA (Recommended)”

The Mikrotik-Rate-Limit vendor-specific attribute (VSA) is the simplest method. The RADIUS server returns this attribute in Access-Accept and RouterOS automatically creates a simple queue for the subscriber.

Attribute format:

Mikrotik-Rate-Limit = "rx-rate[/tx-rate] [rx-burst-rate[/tx-burst-rate] [rx-burst-threshold[/tx-burst-threshold] [rx-burst-time[/tx-burst-time] [priority] [rx-rate-min[/tx-rate-min]]]]]"

All rates are in bits per second. Suffixes: k = kbps, M = Mbps, G = Gbps.

Common examples:

# 20 Mbps down / 5 Mbps up
Mikrotik-Rate-Limit = "20M/5M"
# 100M down / 20M up with burst
# Burst to 150M/30M up to 10M/5M threshold for 10 seconds
Mikrotik-Rate-Limit = "100M/20M 150M/30M 10M/5M 10s"
# 1 Gbps symmetrical
Mikrotik-Rate-Limit = "1G"

RouterOS applies this as a per-PPP-session simple queue, visible in /queue simple.

Note: Mikrotik-Rate-Limit for DHCPv6 bindings requires RouterOS v6.43 or later.

Per-Connection Queuing (PCQ) provides automatic fair-share distribution across subscribers without per-subscriber configuration. Useful for managed contention rather than individual rate limits.

/queue type
add name=pcq-download kind=pcq pcq-classifier=dst-address pcq-rate=10M pcq-limit=50KiB
add name=pcq-upload kind=pcq pcq-classifier=src-address pcq-rate=2M pcq-limit=50KiB
/queue tree
add name=download parent=global packet-mark=subs-down queue=pcq-download
add name=upload parent=global packet-mark=subs-up queue=pcq-upload

Classify traffic with mangle before it reaches the queue tree:

/ip firewall mangle
add chain=forward src-address=100.64.0.0/10 action=mark-packet new-packet-mark=subs-up passthrough=no
add chain=forward dst-address=100.64.0.0/10 action=mark-packet new-packet-mark=subs-down passthrough=no

Method 3 — Queue Tree per Subscriber (Advanced)

Section titled “Method 3 — Queue Tree per Subscriber (Advanced)”

For maximum control, dynamically build queue-tree entries via scripts triggered on PPP login/logout. This is appropriate for large deployments where Mikrotik-Rate-Limit simple queues degrade performance.

Use PPP event scripts (on-up/on-down in the PPP profile):

/ppp profile
set isp-standard \
on-up="/queue tree add name=$user parent=global limit-at=$\"rate-limit\" max-limit=$\"rate-limit\"" \
on-down="/queue tree remove [find name=$user]"
AttributeDirectionEffect on RouterOS
Framed-IP-AddressAccess-AcceptAssign specific IP to subscriber
Framed-PoolAccess-AcceptAllocate from named local /ip pool
Mikrotik-Rate-LimitAccess-AcceptSet upload/download rate (simple queue)
Session-TimeoutAccess-AcceptForce disconnect after N seconds
Idle-TimeoutAccess-AcceptDisconnect after N seconds of inactivity
Mikrotik-Recv-LimitAccess-AcceptTotal download byte cap for session
Mikrotik-Xmit-LimitAccess-AcceptTotal upload byte cap for session
Ascend-Data-RateAccess-AcceptAlternative rate-limit (upstream compat)
Acct-Session-IdAccountingSession correlation identifier
Acct-Input-OctetsAccountingBytes received by subscriber
Acct-Output-OctetsAccountingBytes sent by subscriber
# All active PPPoE sessions
/ppp active print
# Sessions with address and service details
/ppp active print detail
# Count active sessions
/ppp active print count-only
# Active DHCP leases (RADIUS-authenticated)
/ip dhcp-server lease print where radius=yes

Subscriber authenticates but no rate limit applied

Verify Mikrotik-Rate-Limit is in the Access-Accept (check RADIUS server logs). Confirm the attribute uses correct syntax — a malformed value is silently ignored. Check /queue simple to see if RouterOS created a queue entry.

Pool exhausted — new subscribers get no IP

/ip pool print
/ip pool used print

Add ranges to the pool or configure next-pool for overflow. Consider whether stale sessions are holding leases.

Old sessions not disconnecting

Use Disconnect-Message from RADIUS to force termination:

# Verify incoming CoA is enabled
/radius incoming print

High CPU with many subscribers

Simple queues created by Mikrotik-Rate-Limit are processed in order and can become a bottleneck above ~1000 concurrent sessions. Consider PCQ or queue-tree approaches, or upgrade to CCR hardware with multi-core queue processing.