Skip to content

PPPoE ISP Deployment Guide

This guide covers end-to-end PPPoE deployment for Internet Service Providers using RouterOS as a Broadband Remote Access Server (BRAS). It addresses subscriber authentication and accounting via RADIUS, service-tier separation using PPP profiles and service names, user management at scale, and multi-VLAN access topologies.

PPPoE provides ISPs with:

  • Per-subscriber IP assignment and session accounting
  • Centralized credential management via RADIUS
  • Per-session rate limiting and policy enforcement
  • Session lifecycle control (timeouts, simultaneous-use limits)
  • RouterOS 7.x on the BRAS router (CCR or CRS with sufficient CPU for session count)
  • A RADIUS server reachable from the BRAS (FreeRADIUS 3.x recommended)
  • Access network delivering PPPoE frames to the BRAS (Ethernet, VLAN, QinQ)
  • IP address pools sized for expected subscriber density
  • Upstream gateway configured for subscriber traffic routing

Define one or more pools for subscriber address assignment. For ISP scale, use RFC 6598 CGNAT space (100.64.0.0/10) or your allocated public prefixes.

/ip pool
add name=subscribers-pool1 ranges=100.64.0.1-100.64.63.254
add name=subscribers-pool2 ranges=100.64.64.1-100.64.127.254

Multiple pools allow routing each block to a different upstream or PE router. Assign pools to profiles to steer subscriber traffic.

Profiles define the session parameters applied to all subscribers in a service tier. Parameters in a PPP secret override the profile; parameters in the profile override the default profile.

/ppp profile
add name=residential \
local-address=100.64.0.0 \
remote-address=subscribers-pool1 \
dns-server=9.9.9.9,1.1.1.1 \
rate-limit=20M/50M \
session-timeout=0 \
idle-timeout=0 \
change-tcp-mss=yes \
use-compression=no \
use-encryption=no
add name=business \
local-address=100.64.0.0 \
remote-address=subscribers-pool2 \
dns-server=9.9.9.9,1.1.1.1 \
rate-limit=100M/100M \
session-timeout=0 \
idle-timeout=0 \
change-tcp-mss=yes \
use-compression=no \
use-encryption=no
Profile ParameterDescription
local-addressServer-side IP for all sessions using this profile (shared unnumbered address)
remote-addressIP pool name or static IP for subscriber
dns-serverDNS pushed to subscriber via IPCP
rate-limit<upload>/<download> or full burst format — see Rate Limiting
session-timeoutMaximum session duration in seconds; 0 = unlimited. RADIUS Session-Timeout overrides per-session
idle-timeoutDisconnect after this period of no traffic; 0 = unlimited
change-tcp-mssClamp TCP MSS to avoid MTU black holes — recommended for all PPPoE profiles
only-oneyes = enforce single simultaneous session per username (local auth only)

Create one server instance per access interface or per service tier. Multiple instances on the same interface with different service-name values allow tier separation without additional physical interfaces.

/interface pppoe-server server
add name=bras-residential \
interface=bridge-access \
service-name=isp-home \
default-profile=residential \
authentication=pap,chap,mschap2 \
one-session-per-host=yes \
keepalive-timeout=60 \
max-sessions=2000 \
disabled=no
add name=bras-business \
interface=bridge-access \
service-name=isp-biz \
default-profile=business \
authentication=chap,mschap2 \
one-session-per-host=yes \
keepalive-timeout=60 \
max-sessions=500 \
disabled=no
Server ParameterDescription
interfaceInterface or bridge to listen on for PPPoE Discovery frames
service-nameAccess Concentrator service tag sent in PADO/PADS. CPEs filter on this; empty = accept all
default-profileProfile applied when RADIUS does not return a Filter-Id or Mikrotik-Group
authenticationAccepted auth protocols: pap, chap, mschap1, mschap2. Avoid pap if possible — sends plaintext passwords
one-session-per-hostPrevents stale duplicate sessions from the same CPE MAC
keepalive-timeoutSeconds before disconnecting an unresponsive session (LCP echo)
max-sessionsHard cap on concurrent sessions per server instance
ac-nameAccess Concentrator name advertised in PADO (defaults to hostname)

For VLAN-per-subscriber or VLAN-per-aggregation topologies, create a VLAN interface and bind the server to it:

/interface vlan
add name=vlan100-access vlan-id=100 interface=ether2
/interface pppoe-server server
add name=bras-vlan100 interface=vlan100-access service-name=isp default-profile=residential \
one-session-per-host=yes keepalive-timeout=60 disabled=no

For QinQ (double-tagged frames from DSLAM/OLT), create nested VLANs:

/interface vlan
add name=outer-vlan200 vlan-id=200 interface=ether2
/interface vlan
add name=inner-vlan10 vlan-id=10 interface=outer-vlan200

Then bind the PPPoE server to inner-vlan10.

Local secrets are suitable for small deployments or testing. Each entry defines one subscriber account.

/ppp secret
add name=user001 password=secret123 service=pppoe profile=residential
add name=user002 password=secret456 service=pppoe profile=business \
remote-address=203.0.113.10 comment="static IP customer"
add name=user003 password=secret789 service=pppoe profile=residential \
caller-id=AA:BB:CC:DD:EE:FF comment="MAC-locked CPE"
Secret ParameterDescription
service=pppoeRestrict account to PPPoE only; prevents use with L2TP/PPTP secrets
profileOverride default profile for this subscriber
remote-addressAssign a static IP, overriding the pool
caller-idLock account to a specific CPE MAC; rejected if MAC does not match
only-oneyes = allow only one concurrent session per account (per-secret override)
limit-bytes-in / limit-bytes-outByte quota; session is disconnected when reached
routesAdditional routes pushed into the subscriber’s routing table via IPCP

Simultaneous-use enforcement with local secrets is limited to only-one=yes (binary). For integer concurrent-session limits, use RADIUS (FreeRADIUS Simultaneous-Use attribute).

For ISP-scale deployments, move user management to RADIUS. RouterOS acts as a RADIUS client; the RADIUS server authenticates credentials and returns session policy.

/radius
add address=10.0.1.10 secret=SharedSecret123 service=ppp timeout=3000 \
comment="Primary AAA"
add address=10.0.1.11 secret=SharedSecret123 service=ppp timeout=3000 \
comment="Secondary AAA"

RouterOS tries RADIUS servers in list order, failing over on timeout. Set timeout in milliseconds; 3000 ms (3 s) is typical for LAN-attached AAA.

/ppp aaa
set use-radius=yes accounting=yes interim-update=5m
ParameterDescription
use-radius=yesSend Access-Request to RADIUS instead of checking local secrets first
accounting=yesSend Accounting-Start, Accounting-Stop, and Accounting-Interim-Update
interim-updateFrequency of interim accounting records (useful for live session dashboards)

When use-radius=yes and all RADIUS servers are unreachable, RouterOS falls back to local PPP secrets. To prevent fallback in strict environments, remove all local PPP secrets.

RouterOS sends these attributes in Access-Request for PPPoE sessions:

AttributeValue
User-NamePPPoE username
User-Password / CHAP-PasswordPassword (PAP) or challenge response
NAS-IP-AddressRouter’s source IP for RADIUS
NAS-Port-TypeEthernet (15) for PPPoE
Called-Station-IdAC name (router hostname or ac-name)
Calling-Station-IdClient CPE MAC address
Framed-ProtocolPPP (1)
Service-TypeFramed-User (2)

RouterOS applies these attributes from Access-Accept to the PPPoE session:

AttributeEffect
Framed-IP-AddressAssign specific IP to subscriber (overrides pool)
Framed-PoolAssign IP from named local pool
Framed-IP-NetmaskSubscriber netmask (rarely needed for PPP)
Session-TimeoutMaximum session duration in seconds
Idle-TimeoutDisconnect after N seconds idle
Filter-IdApply a named local PPP profile
ClassOpaque string echoed in all accounting packets
Reply-MessageRejection reason logged on auth failure
Mikrotik-Rate-LimitRate limit in U/D format — see below
Mikrotik-Address-ListAdd subscriber IP to a named IP address list
Mikrotik-Recv-LimitByte quota inbound; disconnects on exhaustion
Mikrotik-Xmit-LimitByte quota outbound
Mikrotik-GroupApply named local PPP profile (alternative to Filter-Id)
Mikrotik-Delegated-IPv6-PoolIPv6 prefix delegation pool name

The Mikrotik-Rate-Limit VSA (Vendor 14988, Attribute 1) controls per-subscriber bandwidth. Full format:

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]]]]]

Common examples:

# Simple: 20 Mbps down, 10 Mbps up
"20M/10M"
# With burst: 50M/20M burst to 100M/40M for 10s above 25M/10M threshold
"20M/10M 100M/40M 25M/10M 10s"
# Full with priority and minimum guaranteed rate
"20M/10M 100M/40M 25M/10M 10s 8 5M/2M"

When RADIUS returns Mikrotik-Rate-Limit, RouterOS automatically creates a dynamic Simple Queue for the session. This queue appears in /queue simple as <pppoe-ifname> and is removed on disconnect.

/etc/freeradius/3.0/mods-config/files/authorize:

user001 Cleartext-Password := "secret123"
Framed-IP-Address = 100.64.0.5,
Mikrotik-Rate-Limit = "20M/10M",
Session-Timeout = 86400,
Filter-Id = "residential"
user002 Cleartext-Password := "secret456"
Framed-IP-Address = 203.0.113.10,
Mikrotik-Rate-Limit = "100M/100M",
Filter-Id = "business"

/etc/freeradius/3.0/clients.conf — add the BRAS as a RADIUS client:

client bras-01 {
ipaddr = 10.0.1.1
secret = SharedSecret123
nas_type = other
shortname = bras-01
}

For database-backed subscriber management, configure the rlm_sql module to query a subscribers table and return attributes dynamically.

The simplest approach: set rate-limit in the PPP profile. All subscribers on that profile share the same rate limit.

/ppp profile
set residential rate-limit=20M/50M
set business rate-limit=100M/100M

Return Mikrotik-Rate-Limit from RADIUS per-subscriber for granular control. RouterOS creates a dynamic Simple Queue per session automatically. No additional router configuration is needed.

For advanced QoS requiring a queue hierarchy (parent per-VLAN or per-node), use PPP profile on-up/on-down scripts:

/ppp profile
set residential \
on-up="/queue simple add name=$interface parent=isp-residential \
max-limit=50M/20M target=$\"local-address\"" \
on-down="/queue simple remove [find name=$interface]"

Available script variables in on-up/on-down:

VariableValue
$userPPP username
$interfacePPPoE virtual interface name (e.g., <pppoe-user001>)
$caller-idClient MAC address
$remote-addressAssigned subscriber IP
$local-addressServer-side session IP

Pattern 1: Flat Ethernet Access (Small ISP)

Section titled “Pattern 1: Flat Ethernet Access (Small ISP)”

Single access bridge, all subscribers on one VLAN, local secrets or simple RADIUS.

[OLT/Switch] ──── [BRAS: bridge-access] ──── pppoe-server(isp) ──── RADIUS
subscribers-pool
/interface bridge
add name=bridge-access
/interface bridge port
add bridge=bridge-access interface=ether2 comment="access uplink"
/ip pool
add name=subs ranges=100.64.0.1-100.64.3.254
/ppp profile
add name=residential local-address=100.64.0.0 remote-address=subs \
dns-server=9.9.9.9,1.1.1.1 rate-limit=20M/50M change-tcp-mss=yes
/interface pppoe-server server
add name=bras interface=bridge-access service-name=isp \
default-profile=residential authentication=mschap2 \
one-session-per-host=yes keepalive-timeout=60 max-sessions=250 disabled=no
/radius
add address=10.0.0.10 secret=Secret service=ppp
/ppp aaa
set use-radius=yes accounting=yes interim-update=5m

Pattern 2: VLAN-per-Node Access (Medium ISP)

Section titled “Pattern 2: VLAN-per-Node Access (Medium ISP)”

Each DSLAM, OLT, or distribution node uses a dedicated VLAN. The BRAS terminates each VLAN with a dedicated PPPoE server instance and profile, enabling per-node session accounting and policy.

/interface vlan
add name=node-a vlan-id=100 interface=ether2
add name=node-b vlan-id=101 interface=ether2
add name=node-c vlan-id=102 interface=ether2
/interface pppoe-server server
add name=bras-node-a interface=node-a service-name=isp default-profile=residential \
one-session-per-host=yes keepalive-timeout=60 disabled=no
add name=bras-node-b interface=node-b service-name=isp default-profile=residential \
one-session-per-host=yes keepalive-timeout=60 disabled=no
add name=bras-node-c interface=node-c service-name=isp default-profile=residential \
one-session-per-host=yes keepalive-timeout=60 disabled=no

Calling-Station-Id in RADIUS accounting identifies the CPE MAC; Called-Station-Id identifies the AC name, allowing per-node session reports.

Use different service-name values on the same interface to separate service tiers. CPE devices are configured by the ISP to use the appropriate service name.

/interface pppoe-server server
add name=tier-home interface=bridge-access service-name=home \
default-profile=residential max-sessions=2000 authentication=mschap2 disabled=no
add name=tier-business interface=bridge-access service-name=business \
default-profile=business max-sessions=500 authentication=mschap2 disabled=no
add name=tier-mgmt interface=bridge-access service-name=mgmt \
default-profile=mgmt max-sessions=100 authentication=mschap2 disabled=no

Subscribers that do not specify a service name connect to the server with an empty service-name. To catch unmatched CPEs, add a fallback server with service-name="":

/interface pppoe-server server
add name=tier-catch-all interface=bridge-access service-name="" \
default-profile=restricted disabled=no

For business subscribers requiring a static IP, return Framed-IP-Address from RADIUS, or set remote-address in the PPP secret:

/ppp secret
add name=biz-customer1 password=p@ss service=pppoe profile=business \
remote-address=203.0.113.10

For a static subnet routed to the subscriber, add a route to /ip route pointing to the subscriber’s session interface, or use PPP routes returned by RADIUS (Framed-Route attribute).

Bind subscriber accounts to their CPE MAC to prevent credential sharing:

/ppp secret
set [find name=user001] caller-id=AA:BB:CC:DD:EE:FF

Via RADIUS, include the Calling-Station-Id check in the authorize section:

user001 Cleartext-Password := "secret123",
Calling-Station-Id == "AA:BB:CC:DD:EE:FF"
Mikrotik-Rate-Limit = "20M/10M"

Check active PPPoE sessions:

/ppp active print

View session details including assigned IP, profile, uptime, and bytes:

/ppp active print detail

Monitor PPPoE server instance counters:

/interface pppoe-server server print stats

Verify RADIUS connectivity and packet counts:

/radius monitor 0

Output shows packets sent, accepted, rejected, and timed-out per RADIUS server — confirms the BRAS is reaching the AAA server.

Confirm dynamic Simple Queue was created for a session:

/queue simple print where name~"pppoe"

Check that the subscriber IP was assigned from the expected pool:

/ip pool used print

Enable PPP debug logging to capture the full LCP/IPCP exchange:

/system logging
add topics=ppp,debug action=memory
add topics=pppoe,debug action=memory
/log print follow where topics~"ppp"

Common causes:

SymptomLikely Cause
LCP timeoutCPE not sending PPPoE Discovery; check VLAN tags match on both ends
AUTH failedWrong credentials or RADIUS rejected; check /radius monitor
no pool availableIP pool exhausted; add more ranges or increase max-sessions
session limit reachedmax-sessions on server instance exceeded; increase or add instances
one session per hostCPE already has an active session; check /ppp active for stale entry
RADIUS timeoutFirewall blocking UDP 1812/1813; check timeout value in /radius

Check RADIUS server is reachable:

/radius monitor 0

If timeouts are incrementing, the BRAS cannot reach the RADIUS server. Verify /radius address is correct and that the firewall allows UDP 1812 from the BRAS.

If rejects are incrementing, the RADIUS server is responding with Access-Reject. Check:

  • RADIUS clients.conf has the correct BRAS IP and shared secret
  • Username exists in the RADIUS user database
  • No Calling-Station-Id mismatch (if MAC locking is enabled)

Verify accounting is enabled:

/ppp aaa print

Confirm accounting=yes and use-radius=yes. RADIUS accounting uses UDP port 1813 — ensure it is allowed through any firewall between BRAS and RADIUS server.

If RADIUS returns Mikrotik-Rate-Limit but no Simple Queue appears:

  1. Confirm the attribute is being returned: check FreeRADIUS radacct or enable debug with radiusd -X
  2. Verify vendor dictionary is loaded in FreeRADIUS (dictionary.mikrotik must be included)
  3. Check /log for ppp,info messages about rate-limit parsing errors

PPPoE adds an 8-byte header. On a standard 1500-byte Ethernet MTU, PPPoE sessions have an effective MTU of 1492. Set the PPPoE client interface MTU to 1480 if fragmentation is observed:

# On the BRAS, clamp TCP MSS
/ppp profile
set residential change-tcp-mss=yes
# Verify MSS clamping rule exists
/ip firewall mangle print where chain=forward action=change-mss