Row-level security (RLS) in Power BI filters the data in a report based on who's looking at it, so a sales rep sees their own customers and a branch manager sees their own branch, all from one report. You set it up in three places: define roles with DAX filters in Power BI Desktop (Modeling > Manage roles), test them with View as, then publish and add people or security groups to each role in the Power BI service (the semantic model's More options > Security). It works on a Pro license. The catch most people hit: RLS only restricts people with the Viewer role. Workspace Admins, Members and Contributors see everything.
When you need it
You need RLS when one report serves people who shouldn't see each other's numbers. Some common cases:
- Sales reps who should see only their own pipeline and commissions
- Branch or location managers at a multi-site business
- An accounting firm sharing one dashboard template with several clients
- A manufacturer sharing a supplier scorecard with each supplier
Without RLS the usual workaround is a copy of the report per person, which works until you have to change something in 14 copies.
Static or dynamic
There are two ways to write the rules.
Static RLS hard-codes the value in the role. A role called "West" with the filter [Region] = "West", a role called "East" with [Region] = "East", and you put the right people in each role. It's simple and fine if you have a handful of groups that rarely change.
Dynamic RLS uses one role for everyone and looks up what each person can see based on their sign-in. You keep a small table of who gets access to what, and the filter compares it to USERPRINCIPALNAME(), which returns the signed-in user's account name. When someone joins or moves territory, you change a row in the table instead of editing roles.
If you have more than five or six groups, or the list changes often, go dynamic.
Step 1: Create a role in Power BI Desktop
- On the Modeling tab, select Manage roles.
- Select New and give the role a name. Role names can't contain commas.
- Under Select tables, pick the table to filter. Filter the dimension table (Region, Customer, Branch), not the fact table. The relationship carries the filter through to your sales or transactions.
- Under Filter data, add the rule. The default editor handles simple rules like Region equals West. For anything else, select Switch to DAX editor.
A static rule looks like this:
[Region] = "West"
Each row is checked against the expression. Rows that return TRUE stay visible and everything else is removed for that role.
Step 2: Make it dynamic with a user access table
For dynamic RLS, add a table with one row per person per thing they can see. It can come from a SharePoint list, an Excel file or a database table, whatever your team will actually keep up to date.
| Region | |
|---|---|
| maria@yourcompany.com | West |
| james@yourcompany.com | East |
| priya@yourcompany.com | West |
| priya@yourcompany.com | Central |
Load it into the model and leave it unrelated to your other tables. Then create one role, select your Region table, switch to the DAX editor and use:
[Region] IN
CALCULATETABLE (
VALUES ( UserAccess[Region] ),
UserAccess[Email] = USERPRINCIPALNAME ()
)
That keeps every region listed against the signed-in person's email. Priya sees West and Central; Maria sees West only.
Two finishing touches. Add a second filter in the same role on the UserAccess table itself, [Email] = USERPRINCIPALNAME(), so nobody can browse the full access list. Then hide the UserAccess table from report view.
Step 3: Test it in Desktop
On the Modeling tab, select View as. Tick the role, and for dynamic RLS tick Other user and type someone's email address. The report redraws as that person would see it. Check totals, not only the slicers: if a card still shows the company-wide total, a relationship isn't carrying the filter where you think it is.
Step 4: Publish and assign people
- Publish the report from Desktop.
- In the Power BI service, open the workspace, find the semantic model, select More options (...) and then Security.
- Pick the role and add people by email, or better, add a group.
You can add Microsoft Entra security groups, distribution groups and mail-enabled security groups. Microsoft 365 groups (the kind behind a Teams team) aren't supported and can't be added to a role. Using a security group means IT can manage access through normal onboarding instead of someone remembering to update Power BI.
For dynamic RLS, everyone goes into the one role. The access table decides what they see.
Step 5: Test it again in the service
From the same Security page, select More options (...) next to the role and choose Test as role. You can switch to view as a specific person from there. This catches problems Desktop won't, like an email in your access table that doesn't match how the account is actually signed in.
The mistakes we see most
Testing as yourself while you're a workspace Admin or Member. RLS doesn't apply to Admins, Members or Contributors, so the report looks unfiltered and you assume RLS is broken, or worse, you give report users the Member role and they see everything. Give report readers the Viewer role, or share the report through an app.
Email addresses that don't match the sign-in. USERPRINCIPALNAME() returns the account's user principal name, which isn't always the same as someone's email alias. Guest users from outside your company can come through in a format like name_theircompany.com#EXT#@yourcompany.onmicrosoft.com. Microsoft's advice is to store the exact value the function returns in your access table, and to add guest users to roles directly by email rather than through a group.
Putting someone in two roles. Roles add up. A person in both "West" and "All regions" sees all regions. Keep each person in one role, or go dynamic.
Expecting RLS to hide columns. RLS removes rows. If a salary column shouldn't be visible to some people, that's object-level security, which is a separate setup.
Recreating old roles. If roles were ever set up in the service instead of Desktop, they have to be rebuilt in Desktop.
USERELATIONSHIP in measures. Microsoft notes that measures using USERELATIONSHIP() can throw unexpected errors with RLS turned on. If a measure breaks only for restricted users, check there first.
Licensing
RLS doesn't need anything beyond Pro. Everyone who views a shared report still needs a Pro license, unless the workspace is on a Fabric F64 or larger capacity. Giving someone Build permission on the semantic model so they can analyze in Excel doesn't get around RLS: Viewers with Build permission are still filtered, and so is what they export. If you're weighing license options, see Power BI Pro vs Premium Per User vs Fabric.
RLS also carries through to Copilot. Copilot can only see the data the person asking is allowed to see. More on that in our post on Copilot in Power BI.
When to call someone
Static RLS on a clean model is an afternoon's work. It gets harder when the rules aren't simple: managers who see their whole team, clients who should see several entities, or a model where relationships don't line up. If your relationships need work first, our posts on combining tables in Power BI and relationships on multiple columns are the place to start.
If someone is seeing data they shouldn't right now, treat it as urgent. Our $299 Power BI fix covers it, and you don't pay if we can't fix it. For designing security across a set of reports, see Power BI Advisory.
Sources: Microsoft Learn, Row-level security with Power BI, Row-level security (RLS) with Power BI, Privacy and security for Copilot in Fabric, Power BI licenses.