PPPoE Auth Issues
A subscriber dialed PPPoE, the router answered, then the session dropped with “Authentication failed” or “PPP LCP terminated by peer” in MikroTik’s log. This page walks the five causes ProxPanel rejects an auth request for, in the order the RADIUS server checks them.
Symptoms
Section titled “Symptoms”- MikroTik PPP log:
<pppoe-user>: terminated, authentication failed - Customer phone call: “internet stopped working after I changed the password”
- Subscribers page shows the user offline even though they say they’re trying to connect
radpostauthtable fills withAccess-Rejectrows for the username- RADIUS log (
docker logs proxpanel-radius) repeatsAuth reject (<reason>): <username>
Diagnostic flow
Section titled “Diagnostic flow”-
Tail the RADIUS log while the user retries. Every reject is one line with a categorised reason — you usually have the answer before the user finishes redialling.
Terminal window docker logs -f proxpanel-radius 2>&1 | grep -E "Auth (reject|request|success)" -
Match the reason string in the log against the sections below:
not_found,inactive,expired,wrong_password,password_not_found,unknown NAS,mac_mismatch. -
Confirm with the database. Every rejection writes a row to
radpostauth:Terminal window docker exec proxpanel-db psql -U proxpanel -d proxpanel -c \"SELECT username, reply, authdate FROM radpostauth WHERE username='USERNAME' ORDER BY authdate DESC LIMIT 5;" -
Apply the fix below for the matching cause. Most fixes don’t require a service restart — the next dial attempt picks up the new state.
Cause 1 — Unknown NAS
Section titled “Cause 1 — Unknown NAS”The RADIUS server doesn’t have an entry in nas_devices matching the source IP of the request. Either a new MikroTik was added without being registered, or the BNG started sending RADIUS from a different interface.
Log line:
RADIUS auth: unknown NAS: <bng-private>Diagnostic:
docker logs proxpanel-radius 2>&1 | grep "unknown NAS" | tail -20Then list what NAS rows actually exist:
docker exec proxpanel-db psql -U proxpanel -d proxpanel -c \ "SELECT id, name, ip_address, is_active FROM nas_devices ORDER BY id;"Fix:
-
Note the IP from the
unknown NASlog line. -
In the UI: NAS / Routers → Add NAS — enter the IP, the shared secret, mark active.
-
Or insert directly:
Terminal window docker exec proxpanel-db psql -U proxpanel -d proxpanel -c \"INSERT INTO nas_devices (name, short_name, ip_address, secret, type, is_active) \VALUES ('BNG-1', 'bng1', '<bng-private>', 'StrongSharedSecret', 'mikrotik', true);" -
Reload secrets — the RADIUS server caches
nas_devicesat boot:Terminal window docker restart proxpanel-radius -
Confirm:
Terminal window docker logs proxpanel-radius 2>&1 | grep "Loaded.*NAS"
The NAS IP must be the interface the MikroTik sources RADIUS from, not the router’s WAN. On RouterOS check with /radius print detail — the IP your server sees is the one set in /ip route for the route to the ProxPanel server.
Cause 2 — User not found
Section titled “Cause 2 — User not found”The username sent in User-Name doesn’t match any row in subscribers (after realm stripping).
Log line:
Auth reject (user not found): john@example.netDiagnostic:
docker exec proxpanel-db psql -U proxpanel -d proxpanel -c \ "SELECT id, username, status, expiry_date FROM subscribers WHERE username ILIKE '%john%';"If the username is in the table but the user is dialling something subtly different (typo, missing realm, extra space), Auth reject (user not found) is what you get. Compare the log line’s user string byte-for-byte against the DB row.
Fix:
- Typo: the operator fixes it on the customer’s CPE, or in ProxPanel under Subscribers → Edit → Username.
- Missing realm: check the NAS’s
allowed_realmscolumn. If the BNG is configured to strip a realm on the way in, the barejohnmust exist in the DB; if it isn’t stripping,john@example.netmust exist.
Cause 3 — Account inactive
Section titled “Cause 3 — Account inactive”The subscriber row exists but status != 'active'. Either the operator disabled the account, an automated suspension service ran (overdue invoice, sharing detection), or the reseller was suspended and cascaded down.
Log line:
Auth reject (inactive): john@example.netDiagnostic:
docker exec proxpanel-db psql -U proxpanel -d proxpanel -c \ "SELECT s.username, s.status, s.expiry_date, r.is_active AS reseller_active \ FROM subscribers s LEFT JOIN resellers r ON r.id = s.reseller_id \ WHERE s.username = 'john@example.net';"Check the audit log for the most recent status change:
docker exec proxpanel-db psql -U proxpanel -d proxpanel -c \ "SELECT created_at, user_name, action, description FROM audit_logs \ WHERE description ILIKE '%john%' ORDER BY created_at DESC LIMIT 10;"Fix:
- If the account was intentionally suspended, this is working as designed — collect payment first.
- If it was suspended by the overdue-invoice service in error, Subscribers → Edit → Status → Active, then save.
- If
reseller_active = false, the parent reseller is suspended. Reactivate the reseller under Resellers → Edit → Active — the subscriber stays as it was; you may still need to flip the subscriber back to active separately.
Cause 4 — Account expired
Section titled “Cause 4 — Account expired”expiry_date < today. The subscriber row is active but past its term.
Log line:
Auth reject (expired): john@example.netDiagnostic:
docker exec proxpanel-db psql -U proxpanel -d proxpanel -c \ "SELECT username, status, expiry_date, NOW()::date - expiry_date AS days_overdue \ FROM subscribers WHERE username = 'john@example.net';"Fix:
- Subscribers → action menu → Renew — adds the service’s duration to
expiry_dateand writes arenewaltransaction. - Or, Bulk action → Add Days for a free grace extension. Both push the new date through immediately; the next dial succeeds.
Cause 5 — Wrong password
Section titled “Cause 5 — Wrong password”The username is valid and active, but the Cleartext-Password in radcheck (or the decrypted subscribers.password_plain) doesn’t match what was hashed/sent.
Log line:
Auth reject (MS-CHAPv2 failed): john@example.netor for PAP:
Auth reject (wrong password - PAP): john@example.netDiagnostic:
docker exec proxpanel-db psql -U proxpanel -d proxpanel -c \ "SELECT r.username, r.attribute, r.value FROM radcheck r \ WHERE r.username='john@example.net' AND r.attribute='Cleartext-Password';"Make sure the radcheck Cleartext-Password matches the panel’s stored password. If radcheck has nothing, the RADIUS server falls back to security.DecryptPassword(subscriber.password_plain) — if both are blank, you get Auth reject (password not found) instead.
Fix:
- Subscribers → Edit — the password field shows the current value (decrypted server-side, sent over HTTPS). Compare against what the customer is typing.
- If the customer’s CPE has the wrong password configured, fix it there.
- If you want to reset: type a new password, save. The handler writes both
subscribers.password_plain(encrypted) andradcheck.Cleartext-Password(plaintext for the RADIUS server). Next dial works.
Cause 6 — License at subscriber limit
Section titled “Cause 6 — License at subscriber limit”The license server has flagged the customer as over their tier’s subscriber cap. New activations are blocked; existing subscribers keep authenticating, but creating one and then dialling fails because the row never got created.
Symptom in the log:
License: subscriber limit exceeded (count=1001, max=1000)You’ll usually notice this on the create flow (the UI returns a 403 with a message about the tier limit) before it shows up as an auth failure. If someone is calling the API directly, you may see Auth reject (user not found) because the subscriber was never written.
Diagnostic:
docker exec proxpanel-api curl -s http://localhost:8080/health | jqThe /health payload includes the license tier and current count. Cross-check against the license server:
curl -s -X POST "https://license.proxrad.com/api/v1/license/validate" \ -H "Content-Type: application/json" \ -d '{"license_key":"PROXP-XXXXX-XXXXX-XXXXX-XXXXX","server_ip":"YOUR_IP"}' | jqFix:
Buy more capacity from your tier, or contact info@proxrad.com to upgrade. The block clears as soon as the license server’s max_subscribers is raised — no restart needed.
Cause 7 — MAC mismatch (optional, when MAC binding is enabled)
Section titled “Cause 7 — MAC mismatch (optional, when MAC binding is enabled)”If the subscriber has save_mac = true and a stored mac_address, RADIUS will reject any session from a different CPE MAC.
Log line:
Auth reject (MAC mismatch): john@example.net, expected=AA:BB:CC:DD:EE:FF, got=11:22:33:44:55:66Fix:
- Customer replaced their router → Subscribers → action menu → Reset MAC clears the stored MAC; the next dial re-binds.
- Or uncheck Save MAC on the edit page if MAC binding is more trouble than it’s worth for this customer.
Still stuck?
Section titled “Still stuck?”Capture this and email info@proxrad.com:
# 1. Full RADIUS log around the failure windowdocker logs proxpanel-radius --since=10m > /tmp/radius.log
# 2. The subscriber rowdocker exec proxpanel-db psql -U proxpanel -d proxpanel -c \ "SELECT * FROM subscribers WHERE username='USERNAME';" > /tmp/sub.txt
# 3. Recent radpostauthdocker exec proxpanel-db psql -U proxpanel -d proxpanel -c \ "SELECT * FROM radpostauth WHERE username='USERNAME' ORDER BY authdate DESC LIMIT 20;" > /tmp/postauth.txt
# 4. Version + hardware IDcurl -s http://localhost:8080/healthRelated pages
Section titled “Related pages”- RADIUS Timeouts — when the request never reaches the RADIUS server at all.
- License Errors — when the license itself is blocking new auths.
- NAS / Routers — where to add and edit NAS rows.
- Subscribers — the edit page for status, expiry, password, MAC reset.