- Author: Syed Jahanzaib ~A Humble Human being! nothing else
- Platform: aacable.wordpress.com
- Category: ISP Network Architecture
- Audience: ISP Network Engineers & System Administrators
Disclaimer & Note on Writing Style
Every network environment is unique. A solution that works effectively in one infrastructure may require modification in another. Readers are strongly encouraged to understand the underlying concepts and adapt the guidance according to their own architecture, operational policies, and risk tolerance.
Blind copy-paste implementation without proper validation, testing, and change management is never recommended , especially in production environments. Always ensure proper backups and risk assessment before applying any configuration.
The content shared here is based on hands-on experience from real-world deployments, ISP environments, lab testing, and continuous learning. While I strive for technical accuracy, no technical implementation is entirely free from the possibility of error. Constructive discussion and alternative approaches are always welcome.
Due to professional commitments, it is not always feasible to publish highly detailed or multi-part write-ups. The technical logic and implementation details are written based on my own practical experience. AI tools such as ChatGPT are used only to refine grammar, structure, and presentation , not to generate the core technical concepts.
This blog is not intended for client acquisition or follower growth. It exists solely to share practical knowledge and real-world experience with the community.
Thank you for your understanding and continued support.
Introduction
Intended Audience:
This guide is intended for:
- ISP network engineers managing PPPoE/IPoE subscribers
- Operators using NAS with FreeRADIUS
- System administrators responsible for subscriber policy control
- ISPs planning to scale beyond manual user-based configurations
It is especially useful for teams that:
- ✔ Want centralized package management
- ✔ Need scalable service provisioning
- ✔ Are integrating RADIUS with billing systems
- ✔ Plan to introduce time-based or promotional packages
Prerequisites
Before implementing this design, ensure the following are in place:
- FreeRADIUS installed with SQL module enabled
- MikroTik configured as NAS
- PPPoE authentication integrated with RADIUS
- SQL database connected to FreeRADIUS
- Accounting enabled
This guide assumes a working FreeRADIUS + MikroTik integration.
Table of Contents
- Introduction
- Who This Guide Is For
- Prerequisites
- Understanding the Core FreeRADIUS Tables
- How FreeRADIUS Makes Decisions (Processing Order)
- Step 1 – Creating the User (radcheck)
- Step 2 – Creating a Service Package (radgroupreply)
- Step 3 – Assigning Package to User (radusergroup)
- Step 4 – Adding Package Restrictions (radgroupcheck)
- How the Policy Flow Works in Real ISP Environment
- Role of MikroTik in Service Enforcement
- Testing the Configuration using radclient
- Scaling the Design for Large Subscriber Base
- Understanding radreply and Its Role
- Why radreply Should Not Be Used for Standard ISP Packages
- Group-Based Architecture vs Per-User Model
- When radreply Should Be Used
- Operational Benefits for ISPs
- Best Practice Architecture Summary
Whether you’re running a small community network or a growing regional ISP, this approach helps build a structured and manageable subscriber policy framework. This becomes especially important when managing hundreds or thousands of subscribers.
In ISP environments, managing subscriber services efficiently is just as important as delivering bandwidth. As networks grow from a few dozen users to hundreds or thousands of subscribers, manually assigning policies per user quickly becomes unsustainable.
FreeRADIUS provides a scalable way to design and manage subscriber packages using group-based policy architecture. Instead of defining speed, limits, or access rules individually for each user, ISPs can:
- Create service packages
- Assign users to those packages
- Centrally control policy changes
This approach simplifies:
- ✔ Package upgrades
- ✔ Seasonal offers
- ✔ Bulk migrations
- ✔ Billing integration
In this post, we’ll walk through how FreeRADIUS group policy design works using:
- Radcheck
- Radusergroup
- Radgroupreply
But one of the most confusing parts for many operators is:
- 👉 Where do we create the user?
- 👉 Where do we define the package?
- 👉 Where do we assign the speed?
Many people mistakenly put everything inside one table… and later things become messy when customers increase. Today we’ll simplify this using a real-world ISP scenario.
Let’s say:
- You want to create a 10 Mbps internet package
- And assign it to a user named zaib
Understanding the Core FreeRADIUS Tables:
How FreeRADIUS Makes Decisions (Processing Order)
FreeRADIUS does not randomly apply policies. It processes SQL data in a defined order. Before creating users or packages, it’s important to understand how FreeRADIUS evaluates policies internally. FreeRADIUS processes SQL tables in the following order: To understand how packages work, first understand how FreeRADIUS evaluates users. FreeRADIUS SQL works like a proper ISP business model. Each table has a separate role, just like departments in a company.
How All Tables Work Together
In a typical authentication flow, these SQL tables operate as a layered policy engine rather than isolated components.
When a user attempts to log in, FreeRADIUS first evaluates radcheck for user-specific validation rules such as credentials, expiration settings, or account-level restrictions. If authentication succeeds, the system then checks radreply for any user-specific reply attributes that should be returned directly to the NAS (for example, a custom bandwidth override or a temporary service adjustment).
Next, FreeRADIUS consults radusergroup to determine which service group(s) the user belongs to. Based on that membership, radgroupcheck enforces group-level conditions such as Simultaneous-Use limits, time restrictions, or other policy constraints. If all validation checks pass, the corresponding service attributes from radgroupreply are loaded and returned to the NAS, typically defining bandwidth profiles, VLAN assignments, session parameters, or other package-level settings.
This layered structure separates authentication, user-level overrides, group-based validation, and service delivery into distinct logical stages. The result is a modular and scalable design where:
- radcheck → validates the user
- radreply → applies user-specific service overrides
- radusergroup → maps the user to a package
- radgroupcheck → enforces package restrictions
- radgroupreply → defines package services
This separation of concerns makes the system flexible and maintainable, especially in ISP environments where thousands of subscribers share common packages but still require granular per-user control when needed.
This order becomes critical when both user-level and group-level policies exist. This order is important because it explains why group-based design is scalable and predictable.

Step 1: Create the User (radcheck):
radcheck — “User-Specific Authentication & Control Rules”
The radcheck table stores per-user validation conditions that must be satisfied during authentication. Unlike radgroupcheck, which applies rules at the group level, radcheck applies checks directly to an individual username.
This table is commonly used to define authentication credentials (such as Cleartext-Password), account expiration dates, login time restrictions, or other user-specific control attributes.
In ISP deployments, radcheck typically contains the subscriber’s password and any individual-level overrides — for example, disabling a single account, applying a temporary restriction, or setting a custom limit that differs from the assigned package.
This table is only for login authentication. No speed here. No service here.
Just:
✔ Username
✔ Password
Example:
User:
zaib / abc123
INSERT INTO radcheck (username, attribute, op, value)
VALUES ('zaib', 'Cleartext-Password', ':=', 'abc123');
Now user exists in system ✔
Step 2: Create the 10MB Package (radgroupreply):
radgroupreply — “Service Policy Definitions”
This table defines the service attributes that FreeRADIUS will return to the NAS when a user belongs to a particular group.
Think of radgroupreply as the place where you declare what services a group should receive — for example, rate limits, session times, VLAN attributes, or any other RADIUS reply attributes.
When a user authenticates and is mapped to a group, all matching entries in radgroupreply are sent as reply attributes. For ISPs, this is typically where you define customer package characteristics (e.g., upload/download speeds, bandwidth policy strings, or other NAS-specific flags).
Let’s create:
Package name = 10MB
INSERT INTO radgroupreply (groupname, attribute, op, value)
VALUES ('10MB', 'Mikrotik-Rate-Limit', ':=', '10M/10M');
Now:
Group 10MB = 10 Mbps service
Step 3: Assign Package to User (radusergroup):
radusergroup — “User ↔ Package Mapping”
This table links users to groups (packages) and controls which service profile applies to a subscriber.
Instead of assigning reply attributes individually per user, radusergroup lets you assign one or more groups (or packages) to a username. It also supports a priority field, which determines the order in which packages should be evaluated when multiple memberships exist.
In ISP context, this is where you map a subscriber (zaib, user123) to a tariff plan such as “10MB”, “Night-Unlimited”, or other service offerings. This mapping makes large-scale provisioning and upgrades far easier.
Now we “subscribe” user zaib to this package.
INSERT INTO radusergroup (username, groupname, priority)
VALUES ('zaib', '10MB', 1);
That’s it. No need to touch speed again.
Note on Priority:
The priority field controls which group is evaluated first. This becomes important when a user belongs to multiple groups
(for example: Base plan + Night package).
Lower number = higher priority.
Step 4: Optional Restrictions (radgroupcheck):
radgroupcheck — “Group-Based Conditions / Restrictions”
This table is used to define validation checks and conditions on a service group.
While radgroupreply defines what to give, radgroupcheck defines what to check before assigning the group’s services — for example, simultaneous use limits, time restrictions (e.g., only allow login between certain hours), expiration settings, or NAS filtering conditions.
For ISPs, this is where you enforce business logic like “only 1 session at a time” (Simultaneous-Use), “access allowed only at night,” or other policy limits that depend on subscriber behavior or timing.
Real ISP Example of radgroupcheck
In real ISP deployments, radgroupcheck is typically used for:
- Night packagesWeekend plans
- Ramadan offers
- Session limits
- Access control per NAS
Example: Prevent account sharing
INSERT INTO radgroupcheck (groupname, attribute, op, value)
VALUES ('10MB', 'Simultaneous-Use', ':=', '1');
Example: Night-only package
INSERT INTO radgroupcheck (groupname, attribute, op, value)
VALUES ('NIGHT-10MB', 'Login-Time', ':=', 'Al0100-0800');
How It Works in Real ISP Flow:
When zaib logs into PPPoE, this happens:
🔍Authentication Check
FreeRADIUS checks:
👉 radcheck
Is password correct?
✔ Yes → continue
📦 Package Lookup
FreeRADIUS checks:
👉 radusergroup
Which package?
→ 10MB
🚀 Service Applied
FreeRADIUS checks:
👉 radgroupreply
Finds:
→ 10M/10M
Sends to MikroTik.
MikroTik applies speed.
Done ✔
Role of MikroTik in This Design:
FreeRADIUS does not enforce speed. It only sends policy attributes.
When FreeRADIUS sends:
- Mikrotik-Rate-Limit = 10M/10M
MikroTik dynamically creates a simple queue for the PPP session based on the RADIUS reply.
So:
- FreeRADIUS = Policy Brain
- MikroTik = Enforcement Engine
Visual Flow:
Final Result:
All centrally managed.
Testing via RADCLIENT:
To verify group assignment during live login:
Run:
freeradius -X
You should see:
Found group 10MB
Mikrotik-Rate-Limit := 10M/10M
root@radius:~# echo "User-Name=zaib,User-Password=abc123" | radclient -x localhost:1812 auth testing123 Sent Access-Request Id 112 from 0.0.0.0:58903 to 127.0.0.1:1812 length 62 Message-Authenticator = 0x User-Name = "zaib" User-Password = "abc123" Cleartext-Password = "abc123" Received Access-Accept Id 112 from 127.0.0.1:1812 to 127.0.0.1:58903 length 53 Message-Authenticator = 0xb8ae569d527842c659e6be96831fccc6 Mikrotik-Rate-Limit = "10M/10M"
Scaling Example
Let’s assume:
500 users belong to the 10MB package.
To upgrade:
10MB → 15MB
You update only:
radgroupreply
Instead of modifying 500 individual user entries.
In large ISP environments, this enables bulk upgrades without touching individual subscriber records. This becomes critical during:
- Bandwidth revisions
- Promotional upgrades
- Seasonal packages
In real ISP environments, users often belong to multiple groups
(e.g. Base Plan + Night Plan).
Group priority determines which policy is applied first. This is the operational advantage of group-based design.
Understanding radreply and Why ISPs Should Avoid Using It for Services:
So far we covered:
But there is one more table that often creates confusion:
👉 radreply
(👉 radreply is processed before groups)
So…
- 👉 What is radreply
- 👉 When to use it
- 👉 Why NOT to use it for packages in large ISPs
What is radreply?
radreply is used to assign reply attributes directly to a user. These attributes are processed before group-level policies.
Meaning:
Instead of assigning service via group… You attach service directly to username.
Example:
INSERT INTO radreply (username, attribute, op, value)
VALUES ('zaib', 'Mikrotik-Rate-Limit', ':=', '10M/10M');
Now:
User zaib gets 10Mbps > directly. No group involved.
Important Behavior of radreply:
FreeRADIUS evaluates radreply before group policies. This means per-user attributes may override group policies. This means that if the same attribute exists in both radreply and radgroupreply, the user-level value will take precedence. This is a common cause of speed mismatch issues in production ISP deployments.
If the same attribute exists in both:
- radreply
- radgroupreply
Then radreply may override the group setting. This can result in:
- Inconsistent speeds
- Debugging complexity
Which is why ISPs avoid using radreply for standard packages.
Why This is Bad for ISPs at Scale:
This works fine when you have:
- ✔ 10 users
- ✔ 20 users
But becomes a disaster when you have:
- ❌ 500 users
- ❌ 2000 users
Because now:
Each user carries service logic.
Real ISP Problem:
Let’s say:
You want to upgrade:
All 10MB users → 15MB
If you used radreply:
You must update every user row individually.
Nightmare 😅
radreply = Per User Logic
This is:
Group-Based Model = Scalable:
Correct ISP design is:
User → radusergroup → Group → radgroupreply → Service
Instead of:
User → radreply → Service
radreply vs Group Model
Real-World Analogy:
Think like a cable operator in Karachi.
radreply model:
Every customer has a custom package manually written.
Group model:
You create packages like:
- 10MB
- 20MB
- Night Unlimited
And assign users to them. Much cleaner ✔
Operational Impact:
Best Practice for Large ISPs:
Use:
Avoid putting:
- ❌ Speed
- ❌ Time
- ❌ FUP
- ❌ Suspension
inside radreply
When Should You Use radreply?
radreply is best suited for exceptions, not standard packages.
Valid use cases:
- Static IP assignment
- VIP customers
- Enterprise custom policies
Example:
-
Framed-IP-Address := 203.x.x.x
Avoid using radreply for:
- Speed plans
- FUP policies
- Time-based packages
Final Recommendation
Operational Benefits for ISPs:
Group-based design enables:
✔ Bulk upgrades
✔ Seasonal packages (Ramadan / Night)
✔ Billing integration
✔ Faster provisioning
Without editing individual users.
For growing ISPs:
👉 radreply = individual customization
👉 radgroupreply = business packages
And scalable networks always use packages.
Real-World Benefit for ISPs:
This model helps when:
✔ Customers upgrade frequently
✔ Seasonal packages launched
✔ Night / Ramadan offers needed
✔ Integration with billing required
Instead of manually editing users (which becomes impossible after 500+ customers), you manage services professionally.
Best Practice Summary:
Coming Next:
In upcoming posts, we’ll cover:
👉 Night packages
👉 Ramadan offers
👉 FUP (data limit plans)
👉 Speed boost systems
All using MikroTik + FreeRADIUS.








