What it does
Every action on a row goes through two checks. The privilege check asks whether the user holds the privilege at all; the access check asks whether they have rights on that specific row. Access can come from ownership, role access, shared access or hierarchy access, and any one of them is enough.
Key facts
- Ownership type is fixed at table creation: User or team or Organization. Organisation-owned tables only support Organization or None on their privileges — there's no per-row filtering.
- If a user owns the row, or is a member of a team that owns it, any access level suffices. The business unit the row sits in is irrelevant in that case.
- Role access is where access levels do their work: User level for own and team-owned rows, Business Unit for rows in the same business unit as the user or their team, Parent: Child for descendants, Organization for everything else.
- For roles assigned to teams at User level, the Member's privilege inheritance setting matters. Set to Team privileges only, the user can only use that privilege on rows the team owns.
- Sharing grants access five ways: directly to a user, to a team the user belongs to, to the whole organisation, or inherited from a related row shared with either the user or their team.
- Sharing still requires the privilege check to pass. A share doesn't grant a privilege the user's roles never gave them.
- Each row carries an Owning Business Unit column that defaults to the creating user's business unit. It can't be changed unless record ownership across business units is enabled.
- Microsoft describes sharing as a less performant way of controlling access and harder to troubleshoot because it isn't consistently applied. Sharing with a team is more efficient than sharing with individuals; access teams are more efficient again because they can't own rows or hold roles.
- Changing which business unit owns a row has cascade implications through relationship behaviours.
When to use / skip
Ownership and roles should carry the overwhelming majority of your access model. Sharing is for genuine exceptions — the one deal the specialist needs to see, the case escalated outside its normal team. If sharing has become how routine access works, the model underneath is wrong and you're paying for it in query performance and in every access investigation you'll ever run. Where the exception pattern is predictable and per-row, use an access team template rather than individual shares: same effect, far better behaviour at scale. Organisation-owned tables are right for genuine reference data everyone reads and nobody owns, and wrong for anything else, permanently.
Configuration decisions
- Ownership type per table, made once at creation and unchangeable, which is the biggest single lever in the whole security model.
- Whether the default owner of imported and integration-created rows is a service account, a team, or the real business owner.
- Whether sharing is permitted at all, and if so which roles get the Share privilege.
- Whether Share cascades through relationships, which decides how far one share reaches.
- Whether to enable the Who has access view, which needs IsAccessCheckerAllUsersEnabled and IsAccessCheckerNonAdminAllUsersEnabled set through the OrganizationSettingsEditor tool.
Gotchas
- Heavy sharing degrades query performance because every read has to evaluate the share table alongside everything else. It doesn't fail, it just gets slower, and by the time anyone notices there are millions of share rows.
- Shares are invisible in the ordinary UI. A user has access, nobody knows why, and only Check Access explains it.
- Share cascading through relationships means one share on a parent can grant access to thousands of descendants, and nothing in the sharing dialog says so.
- Organisation-owned tables can't be secured per row later. Teams pick this ownership type for convenience during build and discover the constraint during a security review.
- Integration-created rows owned by a service account are invisible to everyone with User-level access. The integration works, the users see nothing, and it looks like a data problem.
- Turning off a cascading Share behaviour doesn't immediately revoke inherited access — a cleanup system job does that, asynchronously, and it can fail.
Consultant notes
- Make ownership type an explicit, signed-off decision per table during design. It's the one that can't be undone without rebuilding the table.
- Give the client a policy on sharing before go-live: who can share, with whom, and for how long. Without one, sharing becomes the default answer to every access ticket.
- Turn on the Who has access settings in every environment. The half-day of admin buys back every future "why can this person see this" investigation.
- If you inherit an environment with performance complaints, count the rows in the sharing tables early. It's often the answer, and it's rarely the first thing anyone checks.
Worth revisiting if sharing ever gets an expiry mechanism, or if ownership type becomes changeable after creation.