What Is Row-Level Security? Security Definition
Also known as: Row-Level Security, RLS, DP-203, Azure SQL Database security, data engineering exam
On This Page
Quick Definition
Row-Level Security, or RLS, is a way to limit what data someone sees in a database table based on who they are. It works like a filter that hides certain rows from certain users, so each person only sees the information they are allowed to access. This is built directly into the database, not into the application, making security consistent and easier to manage. For example, a sales manager might only see rows for their own region, while a global director sees all rows.
Must Know for Exams
Row-Level Security is a specific topic in the Microsoft DP-203 exam, which is the Data Engineering on Microsoft Azure certification. This exam tests your ability to design and implement data storage, data processing, and data security solutions. RLS appears in the section on implementing security for data solutions.
You need to understand not just what RLS does, but when to use it, how to implement it, and how it compares to other security features like column-level security, dynamic data masking, and encryption. The exam expects you to know that RLS is enforced at the database level, not the application level. You must understand the difference between filter predicates and block predicates.
A typical exam scenario might describe a multi-tenant Azure SQL Database that stores sales data for multiple regions. The question will ask you to choose the correct method to ensure that users from one region cannot see data from another region. The correct answer will involve creating a security predicate function that uses SUSER_SNAME() to capture the user login, mapping it to a RegionID column, and then creating a security policy that applies that predicate to the table.
The exam may also present a scenario where you must decide between RLS and dynamic data masking. Dynamic data masking obfuscates data at the column level, like hiding the last four digits of a credit card number. RLS, on the other hand, hides entire rows.
A question might describe a situation where a user should not even know that certain rows exist. In that case, RLS is the right choice because it filters out the rows entirely, whereas dynamic data masking still shows the row but with masked values. Another common exam scenario involves performance considerations.
You might be asked what to do if RLS is causing slow queries. The expected answer would include creating indexes on the columns used in the predicate and ensuring the predicate function is inline and schema-bound. The exam may also test your understanding of how RLS interacts with other features like Azure Synapse Link or PolyBase.
You need to know that RLS applies to queries executed directly against the database, but may not apply to data exported via external tools if those tools bypass the SQL engine. Questions might also require you to identify the correct T-SQL syntax for creating a security policy, including the CREATE SECURITY POLICY, ADD FILTER PREDICATE, and WITH (STATE = ON) clauses. The DP-203 exam objectives explicitly mention 'Implement row-level security' as a key skill.
This means you should be comfortable writing the code to create a predicate function and applying it. You should also know how to test RLS by connecting as different users and verifying that the expected rows are returned.
Simple Meaning
Imagine you are in a large office building where every employee has an ID badge that grants access to certain floors. The building has many floors, each with different departments. Some employees can go to the finance floor, others can go to the marketing floor, and a few can go everywhere.
Now imagine that the building itself is a database table, and each floor is a row of data. Row-Level Security, or RLS, is like having a security guard at the entrance of each floor who checks your ID badge before letting you in. If your badge does not have permission for that floor, the guard stops you and you never even see what is on that floor.
In database terms, when you run a query to see a table, RLS checks your user identity or role and automatically hides rows that you are not allowed to see. It does not matter if you write a perfect SQL query to request all rows — the database engine silently filters them out before sending the results back to you. This is different from building the filter into the application code, because RLS is enforced at the database level.
Even if someone tries to connect directly to the database with a different tool, the same security rules apply. Think of it like having a special pair of glasses that only shows you the parts of a newspaper that are relevant to your job. The newspaper has many articles, but your glasses blur out anything that is not for you.
The articles still exist in the newspaper, but you simply cannot read them. This approach is extremely useful in multi-tenant systems, where one database stores data for many different customers. Without RLS, you would have to build complex application logic to ensure Customer A never sees Customer B's data.
With RLS, you define a security policy once, and it is automatically applied to every query, report, and export. This reduces the risk of data leaks and simplifies development.
Full Technical Definition
Row-Level Security (RLS) is a feature in Microsoft Azure SQL Database, Azure Synapse Analytics, and SQL Server that enables granular control over access to rows in a database table. It works by using a security predicate, which is a function that defines the logic for filtering rows. This predicate is tied to a security policy, which is then applied to the target table.
The predicate function typically uses built-in functions like SUSER_SNAME() or USER_NAME() to capture the caller's identity, and then compares that identity against a column in the table, such as a Region or CustomerID column. When any query is executed against the table, the database engine automatically appends the predicate logic to the query's WHERE clause. This filtering happens at the storage engine level, meaning the user never sees the filtered rows, not even as an empty result set.
RLS supports two types of predicates: filter predicates and block predicates. A filter predicate silently filters rows out of read operations like SELECT, UPDATE, and DELETE. A block predicate explicitly blocks write operations that violate the predicate, returning an error to the user.
RLS is created using the CREATE SECURITY POLICY statement, which binds the predicate to one or more tables. The predicate function must be a schema-bound inline table-valued function. This design ensures that the predicate cannot be accidentally modified or dropped without affecting the policy.
RLS is an integral part of a defense-in-depth security strategy. It does not replace other security measures like authentication, encryption, or column-level security, but it adds a critical layer of row-level isolation. In Microsoft Azure, RLS is available in Azure SQL Database, Azure SQL Managed Instance, and Azure Synapse Analytics dedicated SQL pools.
It is not currently supported in Azure Synapse serverless SQL pools. Implementing RLS requires careful planning. The predicate function must be efficient because it runs on every row accessed by a query.
Poorly written predicates can cause significant performance degradation. Indexing the columns used in the predicate, especially the column used to compare against the user identity, is essential. RLS also interacts with query plans; the query optimizer may generate different execution plans depending on the predicate.
Testing with realistic data volumes is critical before deploying to production. RLS is commonly used in multi-tenant SaaS applications, where each tenant's data is stored in the same table but partitioned by a TenantID column. By applying a security predicate that filters based on the logged-in user's TenantID, each tenant sees only their own data.
This eliminates the need for separate databases per tenant, reducing cost and administrative overhead. RLS also supports group membership filtering using functions like IS_MEMBER(), which allows you to grant broader access to users in certain Active Directory groups, such as giving managers access to rows for their entire team. This makes RLS flexible enough to handle complex hierarchical access patterns.
Real-Life Example
Think about a large company with a single office building that houses multiple departments: Sales, Marketing, Finance, and HR. Each department has its own section of the building. Employees wear ID badges that include their department and job level.
Now suppose the company stores all its employee records in one big filing cabinet in the basement, but each employee should only see records related to their own department. Without Row-Level Security, you would need a separate filing cabinet for each department, or you would need a clerk to manually sort papers every time someone requested a file. Row-Level Security works like an automated sorting system.
When you walk into the basement and ask for a file, the system reads your ID badge. If you are in Sales, the system only shows you the files that have a Sales sticker on them. It doesn't matter if you ask to see all files — the system only hands you the ones you are allowed to see.
The files for Finance, Marketing, and HR are still in the same cabinet, but they are invisible to you. Now extend the analogy. There are also managers who need to see files from their entire team, even if the team spans multiple departments.
Their ID badge has a special marker that says Manager. The system checks this marker and gives them access to a broader set of files. Now map this to the database. The filing cabinet is your database table.
Each file is a row of data. The ID badge reader is the security predicate. The badge information is the user identity (like SUSER_SNAME()). The department sticker on each file is a column like DepartmentID.
The system's sorting logic is the predicate function that compares your identity to the DepartmentID column. If they match, you see the row. If not, the row is hidden. This analogy also explains why RLS is so powerful: it works automatically and consistently.
You can change the tenant database configuration without rewriting the application, just like you can change the badge reader settings without rebuilding the filing cabinet. The security is enforced at the point of data access, not at the application level, which means even if someone connects using a different tool like Excel or Power BI, the same rules apply. They cannot bypass the sorting system by using a different door.
Why This Term Matters
Row-Level Security matters deeply in real IT work because it solves one of the hardest problems in data management: enforcing data isolation without breaking performance or scalability. In a typical enterprise, a single database often stores data for multiple departments, customers, or partners. Without RLS, developers have to implement security filters in every application, every stored procedure, and every report that accesses the data.
This approach is fragile because a single forgotten filter can expose sensitive data to the wrong user. Auditors and compliance officers demand proof that data is properly isolated, and RLS provides a centralized, auditable mechanism that can be verified. In the context of Azure, RLS is especially important for multi-tenant SaaS applications.
Imagine you are building a platform where hundreds of companies store their customer data in the same database. Each company must only see their own data. Without RLS, you would either need separate databases per tenant (which is expensive and hard to manage) or complex application-level filtering (which is error-prone).
RLS lets you keep a single database while automatically filtering rows per tenant, reducing cost and complexity. From a security perspective, RLS is a key part of a defense-in-depth strategy. It protects against scenarios where a developer accidentally exposes data through a poorly written API endpoint.
Even if the API returns all rows, RLS will strip out the unauthorized ones before the response leaves the database. This gives security teams a safety net. RLS also simplifies reporting and BI integration.
Tools like Power BI and Excel can connect directly to the database and respect RLS policies without any additional configuration. This means business analysts can explore data freely, knowing they cannot accidentally see data they should not see. In regulated industries like healthcare and finance, RLS helps meet compliance requirements such as HIPAA or GDPR.
For example, a hospital database might contain patient records for multiple clinics. Using RLS based on the clinic ID, doctors from one clinic only see their own patients. This ensures patient data is properly isolated, which is a core requirement of HIPAA.
Without RLS, achieving this level of isolation would be much more complex and error-prone. Database administrators also benefit because RLS reduces the need to manage multiple database schemas or security views. Instead of creating separate views for each user role — like SalesView, MarketingView, and FinanceView — you define one security policy on the single table.
This reduces schema clutter and simplifies maintenance. When a new user joins the company, you only need to assign them the appropriate role or group; the RLS policy automatically applies the correct filter.
How It Appears in Exam Questions
In the DP-203 exam and similar Azure data certifications, Row-Level Security appears in several distinct question patterns. The most common pattern is the scenario-based question. You are given a description of a business requirement, such as a company that stores sales data for multiple regions in a single table.
The question asks which security feature you should implement to ensure that regional managers only see data for their own region. The answer choices usually include RLS, column-level security, dynamic data masking, and transparent data encryption. You must recognize that row-level filtering is needed, not just column masking.
Another pattern is the troubleshooting question. A query that previously returned 10,000 rows now returns only 5,000 rows after a security policy is applied. The question asks why this happened.
The answer is that a filter predicate was applied, which silently removes rows that do not match the user's identity. A related pattern asks you to identify which T-SQL command was used to create the policy. You might be shown four CREATE statements and asked to pick the correct one for implementing RLS.
The correct statement will include CREATE SECURITY POLICY with ADD FILTER PREDICATE. The distractors might include ALTER TABLE, CREATE VIEW, or CREATE FUNCTION alone. A more advanced question pattern involves block predicates.
For example, a question might describe a requirement that users from region A cannot insert data that belongs to region B. You need to choose between a filter predicate and a block predicate. The correct answer is a block predicate because it prevents the write operation from succeeding.
Filter predicates only affect read operations. Another pattern combines RLS with performance tuning. A question might describe a situation where RLS was implemented but queries are running slower than expected.
The answer choices include adding indexes, rewriting the predicate function as a multi-statement function, or changing the security policy to use NOCHECK. The correct answer is to add indexes on the columns used in the predicate and ensure the predicate function is an inline table-valued function. The exam also tests your understanding of when NOT to use RLS.
For instance, a question might describe a requirement to hide salary information from junior employees but still show the employee row itself. The correct solution would be column-level security or dynamic data masking, not RLS, because RLS would hide the entire row, which is too restrictive. You must also be aware that RLS applies to all queries, including those from Power BI, Azure Data Studio, and custom applications.
A question might describe a scenario where a user connects via Excel and sees fewer rows than expected. The answer is that RLS is correctly filtering the data based on the user's permissions. Finally, you might encounter questions that require you to identify which built-in function to use in the predicate.
Common functions include SUSER_SNAME(), USER_NAME(), and IS_MEMBER(). You need to know that SUSER_SNAME() returns the SQL login name, USER_NAME() returns the database username, and IS_MEMBER() checks Active Directory group membership. Understanding these functions is critical for writing correct predicate logic.
Study dp-203
Test your understanding with exam-style practice questions.
Example Scenario
You are a data engineer for a company called GlobalRetail, which operates in four regions: North America, Europe, Asia, and South America. The company stores all its sales data in a single Azure SQL Database table called Sales. The table has columns like SaleID, ProductName, Amount, SaleDate, and Region. The company has regional managers who should only see the sales data for their own region. The global sales director, however, needs to see all regions.
You are asked to implement a security solution. You decide to use Row-Level Security. First, you create a schema-bound inline table-valued function called fn_RegionFilter. This function takes no parameters and returns a table with one column. Inside the function, you use SUSER_SNAME() to get the current user's SQL login name. You then map that login to a region using a separate mapping table called UserRegionMap. The function returns a table containing only the Region values that the user is allowed to see. Next, you create a security policy called SalesSecurityPolicy. You bind it to the Sales table using the ADD FILTER PREDICATE clause, referencing your fn_RegionFilter function and using the Region column from the Sales table.
After implementation, you test by connecting as the North America regional manager. You run SELECT * FROM Sales. The query returns only the rows where Region is North America. The rows for other regions are not even visible. You then connect as the global sales director, who is in an Active Directory group called GlobalDirectors. Your predicate function uses IS_MEMBER('GlobalDirectors') to check group membership. If the user is a member, the function returns all regions. The director sees all rows. This scenario demonstrates how RLS provides simple, database-enforced security without requiring changes to any application code. The sales application continues to work exactly as before, but the data returned is automatically limited per user.
Common Mistakes
Thinking that Row-Level Security is applied at the application level, not the database level.
RLS is enforced entirely within the database engine. If you rely on application code to filter rows, a user could bypass the application and connect directly with a different tool, potentially seeing unauthorized data. RLS guarantees that security is enforced no matter how the database is accessed.
Always implement RLS as a security policy in the database itself, not as a WHERE clause in your application code. This ensures consistent enforcement regardless of the client tool.
Using a multi-statement table-valued function instead of an inline table-valued function for the predicate.
Multi-statement functions can cause significant performance degradation because the query optimizer cannot inline them into the outer query. Block predicates also require inline functions. The documentation clearly states that predicate functions must be inline table-valued functions.
Always write the predicate function as an inline table-valued function using a single SELECT statement. Do not declare a table variable or use multiple statements inside the function.
Assuming RLS will protect against all types of data access, including backups or direct data exports.
RLS applies only to queries executed against the database. If you export data using a backup, BCP, or an external ETL tool that connects using a privileged account, the data will not be filtered. RLS is a query-time filter, not an encryption or storage-level security measure.
Understand that RLS is part of a defense-in-depth strategy. Use additional measures like encryption, access control lists, and privileged identity management to secure data at rest and during exports.
Forgetting to add indexes on the columns used in the predicate function, leading to slow query performance.
The predicate function runs on every row accessed by a query. Without an index on the column being compared (e.g., RegionID), the database must scan the entire table. This results in poor performance, especially on large tables.
Create indexes on the columns that are used in the predicate logic. For example, if your predicate filters based on a CustomerID column, create a non-clustered index on that column.
Confusing Row-Level Security with Column-Level Security or Dynamic Data Masking.
These three features solve different problems. RLS hides entire rows. Column-level security restricts access to specific columns (e.g., hiding salary column). Dynamic data masking obfuscates data in a column (e.g., showing XXX-XX-1234 for a Social Security number). Using the wrong feature can break functionality or fail to protect data properly.
Identify the exact requirement: if a user should not see certain rows at all, use RLS. If a user should see the row but not certain columns, use column-level security or dynamic data masking.
Exam Trap — Don't Get Fooled
A question describes a scenario where a user needs to see all rows in a table, but sensitive columns like salary should be hidden from that user. The answer choices include Row-Level Security, Column-Level Security, and Dynamic Data Masking. Many learners choose Row-Level Security because they remember it restricts access, but they overlook that RLS hides entire rows, not just columns.
Always ask yourself: is the requirement to hide a specific column, or to hide rows? If the requirement is to hide data within a column (like masking part of a credit card number), use Dynamic Data Masking or Column-Level Security. If the requirement is to prevent a user from even seeing that a row exists, use RLS.
For the exam, memorize that RLS filters rows, not columns.
Commonly Confused With
Column-Level Security restricts access to specific columns in a table, such as hiding the 'Salary' column from junior employees. Row-Level Security restricts access to entire rows, such as hiding all rows that belong to a different region. Column-Level Security is about vertical restriction, while RLS is about horizontal restriction.
A hospital patient table: Column-Level Security hides the 'Diagnosis' column from billing staff, but they still see the patient's name and ID. Row-Level Security hides entire rows of patients from clinics other than the user's own clinic.
Dynamic Data Masking obfuscates data in a column at query time, such as displaying a phone number as XXX-XXX-1234. The row still appears, but the data is partially hidden. RLS, on the other hand, removes the entire row from the result set. Dynamic Data Masking does not prevent the user from knowing that a row exists or from performing operations on the masked data.
A customer table: Dynamic Data Masking shows the email as j***@example.com for all users, but the row with that email is still visible. RLS would hide the entire row for users who are not allowed to see that customer.
Transparent Data Encryption encrypts the entire database at rest, meaning the data files on disk are encrypted and unreadable without the encryption key. RLS operates at the query level and does not encrypt data. TDE protects against physical theft of the database files, while RLS protects against unauthorized access by users who have legitimate database connections.
If a hard drive is stolen, TDE prevents the thief from reading the data. If a user logs in to the database, RLS prevents them from seeing rows they are not allowed to see. Both are needed for full security.
Application-Level Filtering means the application code adds a WHERE clause to every query to restrict rows. This is done in the application layer, not in the database. RLS is enforced in the database engine itself. Application-level filtering can be bypassed if a user connects directly to the database, while RLS cannot be bypassed by changing the client tool.
A web app adds WHERE Region = 'NorthAmerica' to all queries. If a user connects via SQL Server Management Studio, they can run SELECT * FROM Sales and see all regions. With RLS, the same query from SSMS would still be filtered.
Step-by-Step Breakdown
Identify the filtering requirement
Before implementing RLS, you must clearly define which users or roles should see which rows. For example, regional managers should see only rows where Region matches their assigned region. This step involves mapping user identities to data values, like using a UserRegion table that links login names to region IDs.
Create a schema-bound inline table-valued function
This function contains the filtering logic. It must be schema-bound (WITH SCHEMABINDING) and be an inline table-valued function (returns TABLE as a single SELECT). Inside the function, you use built-in functions like SUSER_SNAME() to capture the current user and compare it against your mapping data. The function returns a table with the same column you will filter on, such as RegionID.
Create a security policy and bind the predicate
Use the CREATE SECURITY POLICY statement. Inside it, use ADD FILTER PREDICATE for read operations, and optionally ADD BLOCK PREDICATE for write operations. You specify the function name and the column from the target table that the function will filter on. For example: ADD FILTER PREDICATE dbo.fn_RegionFilter(Region) ON dbo.Sales. You also specify WITH (STATE = ON) to activate the policy immediately.
Test the security policy with different users
Connect to the database as different users and run SELECT statements against the table. Verify that each user sees only the rows they are supposed to see. Also test INSERT, UPDATE, and DELETE operations if you have block predicates. Ensure that the expected errors or success messages appear.
Monitor performance and add indexes
The predicate function runs on every row accessed. Use execution plans to check for table scans. Create indexes on the columns used in the predicate, such as an index on RegionID. This step is critical for large tables. Also consider compatibility and testing with read replicas if using Azure SQL Database geo-replication.
Maintain and audit the security policy
Over time, user mappings may change. You may need to update the mapping table or the predicate function. Use ALTER SECURITY POLICY to modify or disable the policy. Audit the policy using system views like sys.security_policies and sys.security_predicates. Ensure that documentation is kept up-to-date for compliance purposes.
Practical Mini-Lesson
Row-Level Security is not just a checkbox you turn on; it requires careful planning, implementation, and testing. Let us walk through a complete real-world implementation in Azure SQL Database, focusing on what a data engineer needs to know. The most common use case is a multi-tenant SaaS application.
Imagine you have a table called Orders that stores orders for hundreds of companies. Each order has a TenantID column. You need to ensure that Company A never sees Company B's orders.
The naive approach is to add WHERE TenantID = @CurrentTenantID in every stored procedure and every query in your application. This is error-prone because a single missed query can expose data. RLS solves this centrally.
First, you decide how to identify the current tenant. The simplest method is to create a database user for each tenant's login, and then the predicate function uses USER_NAME() to get the database username. Alternatively, you can use SUSER_SNAME() if each tenant has a unique SQL login.
Another approach is to use an application context, where the application sets a session variable like SET CONTEXT_INFO with the TenantID, and the predicate reads that. Each method has tradeoffs in manageability and security. The most secure approach is to use SQL logins that map to the tenant, because the identity cannot be spoofed by the application.
Next, you write the predicate function. It must be an inline table-valued function. Here is an example: CREATE FUNCTION dbo.fn_TenantFilter(@TenantID INT) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT 1 AS Access WHERE @TenantID = CAST(SESSION_CONTEXT(N'TenantID') AS INT); The SESSION_CONTEXT function reads the value set by the application.
Then you create the security policy: CREATE SECURITY POLICY dbo.OrdersPolicy ADD FILTER PREDICATE dbo.fn_TenantFilter(TenantID) ON dbo.Orders WITH (STATE = ON);. One common mistake is forgetting to set the session context before running queries.
If the context is not set, the predicate returns no rows, and the user sees an empty table. You must build the context-setting into the application's connection logic. Another best practice is to use block predicates for write operations.
For example, if you do not want Tenant A to accidentally insert a row with TenantID = 2, you add a block predicate: ADD BLOCK PREDICATE dbo.fn_TenantFilter(TenantID) ON dbo.Orders.
This will prevent the insert and return an error. Performance is a major concern. The predicate function must be efficient. Avoid using functions like GETDATE() in the predicate because they are evaluated per row and prevent index usage.
Index the column used in the predicate, such as TenantID. Also consider partitioning the table if it is very large, though partitioning is orthogonal to RLS. RLS works with indexing, so a non-clustered index on (TenantID, OrderDate) can dramatically improve query performance.
Finally, test thoroughly. Use different user accounts to log in and verify that the correct rows are returned. Also test edge cases like new tenants with no data, or users who should see all rows (like a super admin).
For super admin access, you can modify the predicate to return all rows if the user is a member of a specific Active Directory group using IS_MEMBER(). This makes RLS flexible without requiring separate tables or policies. In summary, RLS is a powerful tool, but it demands careful design, rigorous testing, and ongoing maintenance.
When implemented correctly, it simplifies security, reduces application complexity, and provides a strong audit trail.
Memory Tip
Remember RLS as 'Rows are like rooms in a hotel: your key only opens your room door. The database is the hotel, the security policy is the lock, and the predicate function is the key card reader.'
Covered in These Exams
Related Glossary Terms
Two-factor authentication (2FA) is a security method that requires two different types of proof before granting access to an account or system.
An A record is a DNS record that maps a domain name to the IPv4 address of the server hosting that domain.
802.1X is a network access control standard that authenticates devices before they are allowed to connect to a wired or wireless network.
Frequently Asked Questions
Does Row-Level Security work with Power BI?
Yes, Power BI can respect Row-Level Security defined in Azure SQL Database. When you import data or use DirectQuery, Power BI passes the user's identity to the database, and the RLS policy filters the rows accordingly. This allows report creators to build dashboards that automatically show the right data to each viewer.
Can I apply Row-Level Security to an existing table without downtime?
Yes, you can create the security predicate function and the security policy while the table is in use. The policy takes effect immediately when you set STATE = ON. However, you should test the policy on a non-production environment first to verify performance and correctness, because the policy will affect all subsequent queries.
Does RLS affect backup and restore operations?
No, RLS does not affect backup and restore. A backup contains all rows regardless of any security policies. When you restore the database, the security policies are restored as well, but they are not active until you set STATE = ON. This is important to know for disaster recovery planning.
Is there any performance overhead from using RLS?
Yes, there is overhead because the predicate function runs on every row accessed by the query. The impact depends on the complexity of the predicate and whether the columns used are indexed. Simple predicates on indexed columns have minimal overhead. Poorly designed predicates on unindexed columns can cause significant performance degradation.
Can I use RLS with Azure Synapse Analytics?
RLS is supported in Azure Synapse Analytics dedicated SQL pools but not in serverless SQL pools. In dedicated pools, you create the security policy and predicate exactly as in Azure SQL Database. However, performance testing is especially important in Synapse because of the massive scale of data.
What is the difference between a filter predicate and a block predicate?
A filter predicate silently filters rows out of read operations (SELECT, UPDATE, DELETE). The user does not see the filtered rows and receives no error. A block predicate prevents write operations (INSERT, UPDATE, DELETE) that would violate the predicate, returning an error to the user. Both are defined in the same security policy.
Can I apply multiple security policies to the same table?
No, you can only have one security policy per table at a time. However, a single security policy can contain multiple predicates — both filter and block — and you can use complex logic in the predicate function itself to handle multiple conditions.
Summary
Row-Level Security is a foundational feature for controlling data access in Microsoft Azure SQL Database and Synapse Analytics. It allows you to define a security policy at the database level that automatically filters rows based on the identity of the user executing a query. This means you can store data for multiple tenants, departments, or regions in a single table while guaranteeing that each user only sees the data they are permitted to access.
The implementation involves creating a schema-bound inline table-valued function that captures the user identity and compares it against a column in the table, then binding that function to the table via a security policy. RLS is distinct from column-level security and dynamic data masking, which restrict access to columns rather than rows. For the DP-203 exam, you must understand when to use RLS, how to write the predicate function correctly, and how to optimize performance with indexing.
You should also be aware of the difference between filter and block predicates, and how RLS interacts with other tools like Power BI. The common pitfalls include confusing RLS with other security features, writing inefficient predicate functions, and neglecting to test with different user accounts. When applied correctly, RLS simplifies application development, strengthens security, and meets compliance requirements.
As a data engineer, mastering RLS is essential for building secure, scalable, and maintainable data solutions in Azure.