All Posts

Data & Analytics

Row-Level Security, Explained: How Snowflake, Databricks and BigQuery Differ

Row-Level Security, Explained: How Snowflake, Databricks and BigQuery Differ

Bhavika J

Editorial Team

What row-level security actually does

Most companies do not want every person who can query a table to see every row in it. A sales table might need regional reps to see only their own territory. A claims table in an insurer might need to hide policyholder identity from an analytics team while leaving it visible to claims processors.

Row-level security and column masking solve this without copying the table. Instead of maintaining a separate, permission-scoped table per audience, the warehouse applies a policy at query time. The underlying data never changes. What changes is what a given query is allowed to return, based on who is running it.

Row-level security controls which rows come back. Column masking controls what a visible row shows in a specific column, replacing a real value with a hash, a null, a partial string, or a substitute value depending on who is asking.

Why this exists as its own layer

Before this pattern became standard, teams solved the same problem with views: a view per department that filtered rows or hid columns, built and maintained by hand. That works until the number of access combinations grows past a handful. A healthcare company with clinicians, billing staff, auditors and a data science team needs a different visibility rule for nearly every pair of role and table, and hand-built views do not scale to that combinatorics.

Policy-based row and column security moves the rule out of the view layer and into a declarative policy attached to the table or column itself, evaluated automatically by the query engine. One table, one set of policies, many audiences.

How the three platforms implement it

The mechanism is similar across vendors, but the implementation details differ enough to matter during a platform evaluation.

Snowflake separates the two controls into row access policies and masking policies. A row access policy is a boolean SQL expression evaluated per row using CURRENT_ROLE() or similar context functions, and it decides whether a given row is returned to the session. A masking policy operates on a single column and determines whether a query sees the plain value, a partially masked value, or a fully masked one, based on the same kind of role or context check. Both features require Enterprise Edition or higher.

Databricks implements the same concepts inside Unity Catalog as row filters and column masks. A row filter is a SQL user-defined function registered in Unity Catalog; rows where the function evaluates to false are dropped from the result set. Column masks work the same way at the column level. These can be applied directly to individual tables, or, as of a change that reached general availability on April 28, 2026, through attribute-based access control (ABAC) policies that attach at the catalog or schema level and apply automatically based on governed tags rather than being configured table by table. That shift matters for any company managing hundreds of tables, since it replaces manual per-table policy assignment with a tag-driven default.

BigQuery takes a different starting point: column-level security is built on policy tags rather than on a policy attached directly to the column. A policy tag is created, a masking rule (hashing, nullification, default substitution, email masking, or partial masking) is attached to it, and the tag is then applied to one or more columns. Access is granted through IAM roles, with a Masked Reader role for users who should see masked values and a Fine-Grained Reader role for users who should see the underlying data.

The practical difference: Snowflake and Databricks let you write the access logic as SQL directly against the table, while BigQuery routes it through IAM roles and a separate tagging system shared with its broader Data Catalog. Neither is strictly more capable, but they require different operational habits. A team fluent in SQL-based policy authorship will find Snowflake and Databricks more direct. A team already organized around GCP's IAM structure will find BigQuery's approach a natural extension of controls it already manages elsewhere.

What to look at when evaluating this

A few questions separate a policy that looks fine in a demo from one that survives production use.

Does the policy apply automatically to new tables, or does someone have to remember to attach it? Databricks' move to ABAC-based tagging exists specifically because per-table policy assignment does not scale; the same question applies to any platform being evaluated: is there a default-deny or tag-inheritance mechanism, or is every new table a manual step someone can forget.

What happens at the join? A row filter or mask on one table is straightforward. The harder case is a query that joins a masked table to an unmasked one, or a row filter that depends on a value in a different table. Confirm the platform documents this behavior rather than leaving it to be discovered in an incident review.

Can the masking rule be reversed by a clever query? Fully masked and hashed values are safe. Partial masking and default substitution are weaker and can sometimes be defeated by aggregation tricks (counting distinct masked values, for instance) unless the platform explicitly guards against it.

Is the edition or tier gated? Snowflake requires Enterprise Edition or higher for both features. Confirm this against a current contract before assuming the capability is included.

What commonly goes wrong

The most common failure is not a broken policy, it is an untested one. A masking rule that works correctly for a simple SELECT * can leak the underlying value through a GROUP BY, a WHERE clause on the masked column, or a downstream BI tool that caches results before the policy would normally apply. Any governance rollout should include a query catalog of the ways analysts actually access the table, not just the query used to demonstrate the policy in review.

The second common failure is policy sprawl with no ownership record: dozens of row filters and masks accumulate over years, no one document tracks which policy governs which table, and a platform migration or table rename silently drops protection that no one notices until an audit finds it.

Sources: Snowflake: Understanding Dynamic Data Masking · Snowflake: Understanding Column-level Security · Databricks: Row filters and column masks · Databricks: ABAC GA announcement · Google Cloud: Introduction to data masking · Google Cloud: Restrict access with column-level access control