Misconfigured table permissions are the most common way model-driven apps go wrong after launch. This lesson teaches new makers how Dataverse security roles, privilege types, and access levels work together — with real-world examples, step-by-step role configuration, and a hands-on exercise to test your understanding.

Imagine you've just built a beautiful model-driven app for your sales team. It has clean forms, smart views, and a business process flow guiding reps through each deal stage. You roll it out — and immediately get a panicked message from a sales manager: "My reps can see each other's opportunities. And someone just deleted a record they shouldn't have touched." You've hit the single most common failure point for new model-driven app builders: you forgot to configure table permissions.
Security in Dataverse isn't an afterthought you bolt on at the end. It's a fundamental layer of your data model, right alongside tables, columns, and relationships. When it works correctly, users see exactly what they need and nothing more. They can do exactly what their role requires — and nothing more. When it's misconfigured, you get data leaks, accidental deletions, and frustrated users who either can't access records they need or have far too much power over records they shouldn't touch.
By the end of this lesson, you'll understand how Dataverse's permission model works from the ground up, how to map security roles to specific tables, and how to set the right privilege types and access levels for real-world scenarios. This is the foundation you need before any user ever logs into your app.
What you'll learn:
You should be comfortable with Dataverse basics — what tables, columns, and rows are — before diving in. If you're brand new to Dataverse, start with Dataverse Fundamentals: Tables, Columns, and Rows Explained for Power Apps Makers first. It also helps to have at least one model-driven app to experiment with. If you don't have one yet, Building Your First Model-Driven App: Site Map, Tables, Forms, and Views will get you there quickly.
Before you touch a single checkbox in the security role editor, you need a mental model of how Dataverse enforces access. Think of it like a building's access control system. The building has many rooms (tables). Each employee (user) carries a keycard (security role). The keycard doesn't just say "access granted" or "access denied" — it specifies, for each room, whether the person can enter, read documents, modify documents, remove documents, or shred them entirely. And it also specifies whose documents they can touch: only their own desk, their whole department, or the whole building.
That's the Dataverse security model in a nutshell. Every user in the system must have at least one security role. That role defines, for each table in the environment, which privileges apply and at what access level. No security role means no access — not even read access to the app itself.
Note
Dataverse security applies at the data layer, not the UI layer. Even if you build a form that doesn't show a particular button, a user with the wrong security role can still be blocked by or allowed through the data layer regardless of your UI choices. Always secure the data, not just the interface.
Dataverse security roles are additive. If a user has two roles, they receive the combination of all privileges from both. You can never use a second role to remove a privilege granted by the first. This is important to understand when designing roles — you can't use a restrictive role to cancel out a permissive one.
When you open a security role and look at a specific table's row, you'll see a series of circles or dots across the top. Each column represents one privilege type. Let's go through each one so you know exactly what you're granting.
This allows a user to add new rows to the table. In a sales app, a sales rep needs Create on the Opportunity table to log new deals. Without it, the "New" button either disappears or throws an error.
This allows a user to view existing rows. Read is the most fundamental privilege — without it, a user sees an empty list or gets an access denied error when trying to open a record. Read is a prerequisite for most other actions to be useful.
This allows a user to modify existing rows. In most apps, users need both Read and Write on tables they work with. A customer service agent, for example, needs Write on Case records to update their status.
This allows a user to permanently remove rows. Be very conservative with Delete. Most frontline users should not have it. You'd typically grant Delete only to managers, administrators, or automated processes — and often only at a restricted access level.
These two privileges work as a pair and govern relationships between records. They're easy to confuse with Read and Write, but they control something specific: whether a record can be linked to another record.
Append means "this record can be attached to another record." For example, a Note record can be appended to a Contact record. The user writing the note needs Append on the Note table.
Append To means "another record can be attached to this record." The user also needs Append To on the Contact table to allow notes to be linked there.
If you find that related records aren't saving correctly — for example, a user creates a note but it doesn't link to the contact — Append/Append To misconfiguration is almost always the culprit.
Tip
As a rule of thumb: if a table participates in a relationship (and most do), users who work with it need both Append and Append To configured appropriately. When in doubt, check both.
These are additional privileges available on most tables. Assign allows a user to change the owner of a record — transferring it to another user or team. Share allows a user to grant another user or team access to a specific record, even if that other user's security role wouldn't normally allow it. These are more advanced and should be granted sparingly.
Now you know what a user can do to a record. Access levels control which records they can do it to. This is where the access scope is defined.
Access levels are set independently for each privilege. So a user might have Read at Organization level (can see all records) but Delete at User level (can only delete records they own). This granularity is powerful.
Here are the access levels from most restrictive to most permissive:
The privilege is completely disabled. The user cannot perform this action on any record in this table, regardless of ownership.
The user can only perform this action on records they own. Ownership in Dataverse means the record's "Owner" field contains that user (or a team the user belongs to). This is the most common level for frontline users — they work their own records and nothing else.
The user can perform this action on records owned by anyone in their Business Unit. Business Units are organizational groupings — roughly equivalent to departments. A manager in the Sales Business Unit with Business Unit-level Read can see all opportunities owned by anyone in the Sales department.
This extends Business Unit access to include all records owned by users in the Business Unit and any child Business Units beneath it in the hierarchy. If your organization has a regional structure (e.g., North Sales → Chicago Sales, Detroit Sales), a regional manager might need this level.
This grants access to all records in the table across the entire environment, regardless of who owns them. Use this level very carefully — it's appropriate for system administrators and certain automated roles, but granting Organization-level access to frontline users typically violates the principle of least privilege.
Warning
It's tempting to set everything to Organization level just to "make things work" when troubleshooting. Resist this. You'll mask the real problem and ship an app with a serious security flaw. Always configure the minimum access level that meets the business requirement.
Let's walk through what you'll actually see when you open the security role editor, so you're not navigating blindly.
Getting there: In Power Apps (make.powerapps.com), navigate to your environment. In the left-hand navigation, select Settings (the gear icon), then choose Security roles. Alternatively, go to the Power Platform admin center at admin.powerplatform.microsoft.com, select your environment, and under Settings → Users + permissions choose Security roles.
You'll see a list of all existing security roles. Microsoft includes a set of built-in roles like "Basic User," "System Administrator," and "System Customizer." To create a new role, click New role (or + New in the classic editor). Give it a meaningful name like "Sales Representative" or "Helpdesk Agent."
The security role editor opens to a grid with tables listed in rows and privilege types in columns. Each cell shows a circle representing the current access level:
You click a circle to cycle through the access levels. You can also right-click to set a specific level directly. The columns across the top of each table row are, in order: Create, Read, Write, Delete, Append, Append To, Assign, Share.
Note
The security role editor has two interfaces. The newer "modern" editor (available in make.powerapps.com) presents a cleaner grid. The "classic" editor (reached by clicking Edit in classic view) shows more tables and fine-grained privileges, including miscellaneous and customization privileges. For configuring table permissions, both work. For adjusting system-level privileges (like the ability to publish customizations), you may need the classic editor.
Let's walk through a realistic example. You're building an app for a small sales team with three types of users: Sales Representatives, Sales Managers, and System Administrators. Your Dataverse environment has three custom tables: Opportunity, Proposal, and Customer Visit.
Here's what the business requires:
Let's build the Sales Representative security role step by step.
Step 1: Create the role. In Power Apps, go to Settings → Security roles → New role. Name it "Sales Representative." Make sure the business unit is set to the correct BU.
Step 2: Find the Opportunity table. Scroll or search for your Opportunity table in the grid.
Step 3: Set Create. Click the Create circle until it shows User level. Sales reps create their own opportunities.
Step 4: Set Read. Click Read to User level. Reps only read their own records (managers will see all).
Step 5: Set Write. Set to User level. Reps edit their own opportunities.
Step 6: Leave Delete at None. Don't grant delete — reps shouldn't be able to remove opportunities.
Step 7: Set Append and Append To. Set both to User level. This allows proposals and visits to be linked to opportunities the rep owns.
Step 8: Repeat for Proposal. Same settings as Opportunity — Create, Read, Write, Append, Append To at User level. Delete remains None.
Step 9: Configure Customer Visit. Here it's different. Set Create at User (reps log their own visits). Set Read at Business Unit (reps can read all visits in the team). Set Write at User (they only edit their own). Leave Delete at None.
Step 10: Add the Basic User role's core privileges. Don't forget: your users also need access to run a model-driven app at all. The built-in Basic User role grants the privileges needed to log into the environment and use common tables. You can either assign both roles to each user, or copy Basic User's core privileges into your custom role. The easier path for most teams is to assign both roles.
Key insight
You must also grant your security role access to any standard Dataverse tables your app uses indirectly. For example, if your forms show related Contacts or Accounts, your role needs at least Read access on those tables too. Missing these is a very common source of mysterious "Access Denied" errors.
For the Sales Manager, repeat the process with the following changes:
Notice how the access levels cleanly express the business logic. We're not just toggling on/off — we're controlling scope.
A security role does nothing until it's assigned to a user. To assign a role:
You can also assign roles to Teams (groups of users), which is a far more scalable approach for larger organizations. When a role is assigned to a team, all members of that team inherit those privileges. This lets you manage access for a hundred sales reps by updating a single team assignment. For more on the relationship between business units, teams, and security roles, see Dataverse Security: Business Units, Security Roles, and Teams.
Tip
After assigning a role, always test with a dedicated test user account (not your admin account) that has only that role. Admin and system customizer roles have elevated privileges that will mask permission errors. If you test as an admin and everything works, that tells you nothing about what a regular user will experience.
Testing security configurations is non-negotiable. Here's a practical approach:
Create a test user in your Microsoft 365 admin center with a Power Apps license. Assign them only the "Sales Representative" role (plus Basic User). Do not assign any admin privileges.
Open a private/incognito browser window and sign in as the test user. Navigate to your model-driven app.
Work through a checklist:
Work through each scenario systematically. When something fails unexpectedly, check both the table-level privilege AND the access level. Most issues come down to a privilege set to None that should be User, or an access level set to User when Business Unit is needed.
For this exercise, you'll need a Dataverse environment with at least one custom table.
Scenario: You're building a support ticket app. You have two custom tables: Support Ticket and Ticket Comment. Your requirements:
Your task:
When you finish, review your work by asking: does every privilege level reflect the minimum access the business role requires?
"Users can't see anything in the app." Almost always one of two causes: the security role doesn't have Read access on the relevant tables, or the model-driven app wasn't shared with the user's security role. In the app editor (make.powerapps.com), open your app, go to Share, and add the security roles that should access it.
"The New button is missing but the user needs to create records." The Create privilege is missing or set to None. Open the security role, find the table, and set Create to at least User level.
"A user can see records they shouldn't." The Read access level is too broad. Check whether it's set to Business Unit or Organization when it should be User. Remember: a user-level Read means they only see records they own.
"Notes or comments aren't saving to the record." This is an Append/Append To problem. The user creating the note needs Append on the Note table. The user (or the role) also needs Append To on the parent table (e.g., Contact or Ticket). Set both to at least User level.
"We gave users two roles and now they have too much access." Remember that roles are additive. If one role grants Organization-level Read on a table, a second role can't restrict it. Audit your role assignments and consolidate if needed. You may need to remove the overly permissive role.
"Everything works in my testing but users are complaining." You probably tested as a System Administrator. Admins bypass most security checks. Always test as a plain user with only the intended roles assigned.
Warning
Never assign the System Administrator or System Customizer role to regular users as a "quick fix" to permission problems. These roles grant unrestricted access to all data and customization capabilities in the entire environment. Use them only for IT administrators.
For more advanced scenarios — like restricting access at the column level rather than the table level — see Column-Level Security and Record Sharing in Dataverse. And if you need to understand how site map navigation can also be tailored by role, Configuring Model-Driven App Site Maps: Navigation Areas, Groups, and Subareas for Role-Based Menu Structures covers that pattern well.
You've covered the full mental model of Dataverse table permissions: how security roles work as the keycard that controls access to every table in your environment, what each privilege type actually governs, and how access levels define the scope of that access — from a user's own records all the way to every record in the organization.
The key principles to carry forward:
From here, there are two natural directions to explore. First, if your app involves sensitive columns — salary figures, personal identification numbers, medical data — you'll want to go deeper on Column-Level Security and Record Sharing in Dataverse, which lets you lock down individual fields rather than entire tables. Second, if you're working within a multi-department organization with hierarchical Business Units, Dataverse Security: Business Units, Security Roles, and Teams will show you how to design your organizational security structure from the top down.
Security configuration is one of those things that feels tedious until it prevents a serious incident. Get it right early, test it thoroughly, and your model-driven app will be something users can trust — not just something they can use.