Row-Level Security in Power BI
Scope the model by who is viewing it
Row-level security (RLS) limits which rows a viewer can see through static or dynamic roles. Dynamic roles read the user's identity against a lookup table to scope data per person.
What you will learn
- Create a static role with a DAX rule
- Build a dynamic role from a user-data lookup
- Explain how RLS does and does not protect data
What is this?
Row-level security applies a DAX filter to a table for a given role: a rule like [Region] = 'west' shows only west rows. Dynamic RLS swaps the literal for a function like USERPRINCIPALNAME() and matches the logged-in user's row in a permissions table. RLS governs viewing in the service; it is not a substitute for encryption, and it can be bypassed by a model author who rebuilds the dataset.
Why do you need it?
- Compliance (regional, per-client data separation) without duplicating datasets per group.
- One certified model serves every team with per-person scoping.
- Dynamic RLS updates when staff change, without editing reports.
- Interview and platform questions about it are common in BI-adjacent roles.
Mental model
Keycards opening specific doors
RLS roles
Everyone enters the same building (the dataset), but your keycard (role) opens only the doors (rows) for your responsibility. A temptation to store -everything- behind one key means the security is decorative.
How it works
- Define a role in the model (e.g. 'West Managers').
- A DAX rule filters the fact or dimension table for that role.
- Add users to the role in Power BI Service.
- Dynamic rules read USERPRINCIPALNAME() or USERNAME() and join to a users-to-scope table.
- Developers with Build permission to the dataset can override RLS by editing the model.
How a dynamic RLS rule scopes data.
Examples
Dynamic RLS role rule
Role: Regional Manager Security table: Permissions[user_email, Region]Rule on Region table: [Region] IN LOOKUPVALUES( Permissions[Region], Permissions[user_email], USERPRINCIPALNAME() )The rule looks up the caller's email in the permission table, returns the regions that user manages, and filters the Region dimension so every visual in the model reflects only those rows.
In production
- A multinational retailer gives each country's managers a role filtering by country table, staff moves handled by the identity source.
- A customer-success product scopes dashboards so each customer sees its own metrics, using a permission table updated from the CRM nightly.
- A hospital keeps patient rows scoped to unit managers by a dynamic role matching their OU.
Best practices
- Put RLS rules on dimension tables, not the fact, so every path benefits.
- Use dynamic rules with a dedicated permissions table kept in sync by an external process.
- Restrict dataset Build permissions so RLS cannot be bypassed by rebuilding the model.
- Test roles as a non-admin user in the service before rollout.
Common mistakes
- Filtering only the fact while dimensions leak the full attribute list.
- Hard-coding usernames in rules instead of a lookup table, creating drift.
- Giving everyone 'member' access to a dataset that carries sensitive rows.
- Forgetting that RLS never hides a downloaded .pbix whose model you can reopen.
Common issues
A user sees all rows even after adding them to a roleThey were also assigned a role without restrictions or dataset-level viewer role
Check the user's membership in other roles and dataset sharing settings.
Dynamic RLS returns blank for some usersUSERPRINCIPALNAME does not match the permission table entries
Normalize casing and trim both sides, then re-add missing names.
RLS works on the report but not on a dashboard tileThe tile predates the RLS change and is cached
Republish the dataset and refresh the dashboard tiles.
Debugging tips
- In Desktop, click Role > View as role to simulate a viewer before publishing.
- Check the permission table's join key matches USERPRINCIPALNAME byte-for-byte.
- Verify that RLS auto-rules use a unique key (one row per user-scope pair).
- Test at least two roles against one visual to confirm no data leak.
Interview checkpoint
Quick quiz
Which function reads the identity of the current viewer in a dynamic RLS rule?
RLS completely prevents someone with the .pbix file from seeing restricted data.