Row-Level Security: Each Viewer Sees Only Their Own Rows
You built one good report. Now five country managers want it — and each of them should see their own country, not everyone's.
Until now you had two bad options: build five copies of the report and keep them in sync forever, or give everyone everything and hope nobody looks. Row-level security removes both. You keep one report. Each Viewer opens it and sees only the rows you've allowed them to see.
What it looks like
Take a sales report on the Northwind sample data. It has total sales, total profit, units sold, sales by country and sales by month.
- You (an Admin or Editor) open it and see every country: $118.7M in sales.
- Your Canada manager opens the same report and sees Canada only: $24.9M. The bar chart has one bar. The monthly trend is Canada's trend.
- Your Germany manager sees Germany only.
Nobody gets a different report and nobody can switch the filter off. At the top of the report, the Viewer sees a short note: Filtered for you — Country: Canada. That way they know why their totals are smaller than the company's.
Setting it up
Row security is set per report, in the report itself. It takes about a minute per person:
- Give the person the report. Add them to the workspace as a Viewer, or share the report with them.
- Open the report and choose More → Row security.
- Choose the reader, then the datasource. For SQL Server, also choose the table.
- Choose the column that decides access — Country, Region, Branch, Account Manager…
- Tick the values they may see. The list is filled from your real data, so there's nothing to type.
- Choose Add rule.
Give someone more than one value (Canada and Mexico) and they see both. Give them rules on two columns (Country = Canada and Segment = Enterprise) and they see the rows that match both.
Rules belong to the report. If you share a second report built on the same protected data, give each reader a rule on that report too: until you do, they see no rows from it.
"Only my own records": the @me rule
Some data has an owner on every row — an account manager's email on each deal, an engineer's email on each ticket. For such a reader, tick Match the reader's own email (@me) instead of picking values: they see the rows that carry their own email address. Set it once per reader, and their rows follow the data as new deals or tickets are assigned to them.
Who is filtered — and who isn't
Row-level security applies to a report's readers:
| Who | What they see |
|---|---|
| Workspace Viewer | Only the rows that report's rules allow them |
| Someone the report was shared with | Only the rows that report's rules allow them |
| Editor | Everything — they build and fix the reports |
| Workspace Admin / owner | Everything, and they manage the rules |
| Organization admin | Everything in their organization |
This is deliberate. The people who build a report have to see all of its data to get it right. The people who read it see their part.
It's safe by default
The rules are built to fail closed. When something is unclear, a Viewer sees less, never more:
- A reader with no rule on a report sees no rows from its protected data, not all of them. Forgetting to add someone never exposes everything.
- Protected data is only shown through reports. Once a datasource has rules, readers see it through the reports that grant them rows, not through workspace chat.
- Public links and embeds are switched off for reports on protected data. A public link has nobody signed in to filter for, so it would show every row. You can't publish, share publicly or embed those reports.
- A protected column that's missing from a result (because a Transform step removed it, or a different sheet is being read) means the result is withheld, not shown unfiltered.
Enforced on the server, everywhere
The filter isn't a hidden chart setting, and it isn't an instruction to the AI. It runs on the server, in the one place every piece of data passes through before it reaches anyone. So it covers:
- every chart, table and KPI card in reports and dashboards
- totals and averages, which are calculated from the Viewer's rows only
- answers from the AI assistant and from chat with your data
- CSV exports and the data behind every visual
- the value suggestions the AI uses to understand your columns
How it's enforced depends on the datasource:
- SQL Server and Azure SQL (directly or through the on-premises gateway): before a query runs, every reference to a protected table is rewritten to read only the allowed rows. This happens before any grouping or totals, so "sales by segment" is correct for the Viewer's own rows. Microsoft's own SQL parser does the rewrite, so comments and unusual formatting can't slip past it. A query it can't check isn't run.
- Uploaded Excel and CSV files, file links and REST APIs: rows are filtered as they're read, before anything is drawn or calculated.
The AI is told the Viewer's scope too, so it talks about "your region" instead of presenting their figures as the company's. But the AI never decides what anyone can see. The server does, before the AI is involved.
Every rule added or removed is recorded in your organization's Activity log.
What's supported today
- Supported: SQL Server and Azure SQL (direct or via the gateway), uploaded Excel and CSV, public file links, and REST APIs.
- On SQL Server, rules apply to the tables you choose. If your Viewers' datasource also exposes a view built on a protected table, add a rule for that view too, or leave it out of the datasource's table list.
- Not yet: PostgreSQL, MySQL, SQLite, Power BI semantic models and the other connectors. Row security can't be set on them yet, so don't share reports built on them with people who should see only part of the data. If you need it on one of them, tell us — it helps us decide what comes next.
Try it
Create a workspace, upload a spreadsheet with a Region or Country column, share the report with a colleague, and give them one value in More → Row security. Then ask them to open it.
Your first report is free, with no card and no deadline. Build it now, or read the workspaces and roles guide first.