System Roles + Custom Roles + Secondary Roles
Yesterday we covered RBAC and DAC at the model level. Today we go one layer deeper, into the roles themselves. Every Snowflake account ships with six system-defined roles. On top of that sit your custom roles, and the recommended pattern is to roll them up to SYSADMIN. Then there is the secondary roles mechanism, which lets one session combine privileges from multiple roles at once. When I run SnowPro training at EY, three facts trip up nearly every cohort: ACCOUNTADMIN is not a superuser, SECURITYADMIN (not SYSADMIN) creates network policies, and database roles cannot be activated directly with USE ROLE. Get those three right and the role-hierarchy questions on the exam become free marks. There are usually two or three of them per sitting.
| Term | Plain meaning |
|---|---|
| System-defined role | One of the six roles Snowflake ships in every account: ORGADMIN, ACCOUNTADMIN, SECURITYADMIN, USERADMIN, SYSADMIN, PUBLIC. Built-in privileges. Cannot be dropped. |
| Custom role | A role you create with CREATE ROLE. Best practice is to grant it to SYSADMIN so admins working as SYSADMIN can see and manage the objects it owns. |
| Primary role | The active role for your session. It is the role CURRENT_ROLE() returns, and the only role that can create new objects. |
| Secondary roles | Extra roles activated alongside the primary role using USE SECONDARY ROLES. They add query and DML privileges to the session. They cannot create or own objects. |
| Least privilege | Grant a role only the privileges it needs to do its job. Snowflake’s whole role design exists to support this principle. |
| MANAGE GRANTS | An account-level privilege that lets a role grant or revoke any privilege on any object. The defining privilege of SECURITYADMIN. |
Today’s Concept
Micro-Concept 1: The Six System Roles — What Each One Does
Memorise this table. The exam rarely tests all six in one question, but at least one of them appears every sitting.
| Role | What it does | Position in hierarchy |
|---|---|---|
| ORGADMIN | Organisation-level operations: managing accounts inside an organisation, viewing cross-account usage. Sits separately from the standard hierarchy. Being phased out in favour of GLOBALORGADMIN under the newer organisation-account model. | Not in the standard role hierarchy. |
| ACCOUNTADMIN | Top of the standard hierarchy. Sees billing and credit consumption. Can abort running statements. Inherits both SYSADMIN and SECURITYADMIN. NOT a superuser. | Parent of SECURITYADMIN and SYSADMIN. |
| SECURITYADMIN | Grant management. Holds MANAGE GRANTS. Can grant or revoke any privilege in the account. Creates network policies. Inherits USERADMIN. | Below ACCOUNTADMIN; parent of USERADMIN. |
| USERADMIN | Creates and manages users and roles. Holds CREATE USER and CREATE ROLE account privileges. Does not hold MANAGE GRANTS. | Below SECURITYADMIN. |
| SYSADMIN | Creates and manages warehouses, databases, and other compute and storage objects. The recommended parent for every custom role. | Below ACCOUNTADMIN; parallel to SECURITYADMIN. |
| PUBLIC | The pseudo-role every user automatically has. Every role inherits it. Useful for “everyone in the account can do this” defaults — and dangerous if you forget that. | Bottom of the hierarchy. Inherited by every role. |
A visual of the hierarchy:
ACCOUNTADMIN
/ \
SECURITYADMIN SYSADMIN ← custom roles roll up here
| |
USERADMIN (your custom role hierarchy)
|
PUBLIC ← inherited by everyone
ORGADMIN → separate, not part of the standard hierarchy
Micro-Concept 2: The Network-Policy Trap (SECURITYADMIN, not SYSADMIN)
One specific question keeps reappearing on the exam, almost word for word: “Which role is recommended to create and manage network policies?” The answer is SECURITYADMIN. This is one of the highest-confidence “free mark” patterns on Domain 2 — if you see it phrased this way, lock in SECURITYADMIN and move on.
The trap is that the word “network” sounds infrastructural, so the brain reaches for SYSADMIN. The reasoning behind the correct answer:
- Per the Snowflake docs on
CREATE NETWORK POLICY, only SECURITYADMIN or higher, or a role with the globalCREATE NETWORK POLICYprivilege, can create one. - SECURITYADMIN holds
MANAGE GRANTS. It is Snowflake’s designated security and access-management role — restricting network access fits squarely inside that scope. - SYSADMIN owns warehouses and databases. That is compute and storage, not security policy.
- USERADMIN handles users and roles. Different domain again.
ACCOUNTADMIN can create network policies, because it inherits SECURITYADMIN. But the documented best-practice answer is SECURITYADMIN. Least privilege says don’t reach for ACCOUNTADMIN when a more specific role does the job.
Micro-Concept 3: ACCOUNTADMIN Is NOT a Superuser
This is the single most-missed Domain 2 fact in my training sessions. ACCOUNTADMIN sits at the top of the hierarchy, but it cannot, by default, modify or drop objects owned by a custom role that lives outside its inheritance chain.
-- A custom role exists in isolation by default
USE ROLE USERADMIN;
CREATE ROLE rogue_r;
-- ACCOUNTADMIN cannot inherit rogue_r's privileges unless rogue_r is granted to it
-- (directly or via the SYSADMIN chain)
USE ROLE ACCOUNTADMIN;
USE ROLE rogue_r; -- only works if rogue_r is granted to ACCOUNTADMIN
-- If rogue_r created a table, ACCOUNTADMIN cannot drop it directly.
This is the whole reason the “grant every custom role to SYSADMIN” rule exists. Without that grant, you end up with orphan roles whose objects sit invisible to anyone except an ACCOUNTADMIN with an explicit grant. In production, that becomes an incident waiting to happen — the role’s owner leaves the team, the role gets dropped, and suddenly nobody can manage the objects underneath.
The practical rules Snowflake documents:
- Do not make ACCOUNTADMIN anyone’s default role. Snowflake explicitly recommends against it in the access control best-practices doc.
- Limit ACCOUNTADMIN to roughly two users. Enough for redundancy if one person is locked out; few enough that the role is not used casually.
- Require MFA for every ACCOUNTADMIN user. Snowflake’s MFA rollout makes this enforced rather than recommended on most accounts now.
- Roll custom roles up to SYSADMIN so the SYSADMIN view of the account is complete.
Micro-Concept 4: Custom Role Hierarchy — The Recommended Shape
Snowflake documents a four-step pattern for creating a custom role. The exam tests recognition of this pattern, not the exact sequence of statements.
- Use USERADMIN to create the role. Plain
CREATE ROLEneeds theCREATE ROLEaccount privilege. USERADMIN has it. - Use SECURITYADMIN to grant privileges to the role. Granting privileges needs
MANAGE GRANTS, which SECURITYADMIN holds. - Grant the new role to SYSADMIN. This is the line that makes the role visible to anyone administering as SYSADMIN.
- Grant the new role to the users who need it. Without this final grant the role exists but nobody can use it.
A working example end to end:
USE ROLE USERADMIN;
CREATE ROLE finance_analyst_r;
USE ROLE SECURITYADMIN;
GRANT USAGE ON WAREHOUSE lab_xs TO ROLE finance_analyst_r;
GRANT USAGE ON DATABASE sales_db TO ROLE finance_analyst_r;
GRANT USAGE ON SCHEMA sales_db.finance TO ROLE finance_analyst_r;
GRANT SELECT ON ALL TABLES IN SCHEMA sales_db.finance TO ROLE finance_analyst_r;
-- Roll the custom role up to SYSADMIN (visibility / management)
GRANT ROLE finance_analyst_r TO ROLE SYSADMIN;
-- Hand it to a user
GRANT ROLE finance_analyst_r TO USER alice;
If you only commit two sentences from this section to memory, make it these: USERADMIN creates roles. SYSADMIN is the recommended parent. Almost every custom-role question on the exam answers to one of those two facts.
Micro-Concept 5: Secondary Roles — Multiple Roles in One Session
Without secondary roles, a session has exactly one active role: the primary role. Switching means running USE ROLE other_r, which replaces the current role completely. The moment you need a JOIN across two tables owned by different roles, this becomes painful.
Secondary roles solve that. The syntax is straightforward:
USE SECONDARY ROLES { ALL | NONE | role1 [, role2 ...] }
Three modes:
| Mode | Effect |
|---|---|
ALL | Activates every role granted to the user as a secondary role. Query authorisation becomes the union of primary plus all granted roles. |
NONE | Disables secondary roles entirely. Only the primary role’s privileges authorise SQL. |
role1, role2, … | Activates a named subset. Each named role must already be granted to the user. |
Three facts the exam tests repeatedly:
- Only the primary role can CREATE objects. Secondary roles add query and DML privileges. They do not create. They do not own. This is the most-tested nuance of the whole feature.
- The set of secondary roles re-evaluates on every SQL statement. Grant a role mid-session and it takes effect on the next statement. Revoke one and it disappears the same way.
- The default for new users is now
'ALL'. BCR-1692 (rolled out from August 2024 through March 2025) changedDEFAULT_SECONDARY_ROLESfromNULL(which behaved as no secondary roles activated) to('ALL'). A fresh user now starts every session with every granted role active. CheckSHOW USERSfor thedefault_secondary_rolescolumn to confirm what your account is on.
One observation from production: this BCR change quietly broke a lot of RBAC implementations that assumed a user could only see one database at a time. If your organisation runs least-privilege strictly and tested it pre-2024, retest it. The third bullet above is exactly the kind of “small change, big consequence” item that shows up as a tricky scenario question on newer exam forms.
Inspect the current state of any session:
SELECT CURRENT_ROLE(); -- the primary role
SELECT CURRENT_SECONDARY_ROLES(); -- a JSON: {"roles": "...", "value": "ALL"|"NONE"|...}
Cheat Sheet
| Concept | What to remember |
|---|---|
| System roles (six) | ORGADMIN, ACCOUNTADMIN, SECURITYADMIN, USERADMIN, SYSADMIN, PUBLIC |
| ORGADMIN scope | Organisation-level (managing accounts within an org). Not in the standard role hierarchy. Being phased out for GLOBALORGADMIN. |
| ACCOUNTADMIN | Top of standard hierarchy. Sees billing. NOT a superuser — does not auto-own objects from custom roles outside its chain. |
| SECURITYADMIN | Holds MANAGE GRANTS. Creates network policies. Inherits USERADMIN. |
| USERADMIN | Creates users and roles. Holds CREATE USER and CREATE ROLE. Does NOT hold MANAGE GRANTS. |
| SYSADMIN | Creates and manages warehouses and databases. Recommended parent for every custom role. |
| PUBLIC | Default for every user. Every role inherits it. Pseudo-role — cannot be dropped. |
| Network policy creation | SECURITYADMIN (or higher, or global CREATE NETWORK POLICY). NOT SYSADMIN. |
| Custom role best practice | USERADMIN creates → SECURITYADMIN grants privileges → GRANT ROLE custom_r TO ROLE SYSADMIN → grant to user. |
| Secondary roles syntax | USE SECONDARY ROLES { ALL | NONE | role1, role2 } |
| Secondary roles & CREATE | Only the primary role creates objects. Secondary roles add query and DML privileges only. |
| Default secondary roles | Default for new users is now 'ALL' (changed in 2024 via BCR-1692). |
| Inspect current roles | CURRENT_ROLE() + CURRENT_SECONDARY_ROLES() |
| Least privilege | Do not make ACCOUNTADMIN a default role. Require MFA. Limit to ~2 users. |
Four traps to memorise verbatim:
(1) “SYSADMIN creates network policies.” FALSE. SECURITYADMIN does. SYSADMIN is the warehouses-and-databases role. (2) “ACCOUNTADMIN is a superuser and can modify any object.” FALSE. ACCOUNTADMIN is the top role but cannot, by default, modify objects owned by a custom role outside its inheritance chain. (3) “USERADMIN can grant any privilege.” FALSE. USERADMIN creates users and roles. It does not hold MANAGE GRANTS — that lives with SECURITYADMIN. (4) “Secondary roles can create objects.” FALSE. Only the primary role creates objects; secondary roles only add query and DML privileges. One more trap aimed at the newer C03 emphasis on secondary roles: when a question asks “which role owns the newly created table” under USE SECONDARY ROLES ALL, the answer is still the primary role. When I sat the DEA-C02 exam, this exact ownership question appeared with secondary-role distractors — the same pattern carries straight into the Core paper.
Hands-On Lab
Inventory the system roles. Every trial account ships with the same six.
USE ROLE ACCOUNTADMIN;
USE WAREHOUSE lab_xs;
-- The six system-defined roles (plus any custom roles already created)
SHOW ROLES;
-- Look for ORGADMIN, ACCOUNTADMIN, SECURITYADMIN, USERADMIN, SYSADMIN, PUBLIC
is_default column shows which role activates when you log in.Switch between SECURITYADMIN and SYSADMIN and compare visibility.
USE ROLE SECURITYADMIN;
SHOW DATABASES;
-- SECURITYADMIN typically sees account-level objects but may not see all databases owned by custom roles
USE ROLE SYSADMIN;
SHOW DATABASES;
-- SYSADMIN sees databases it owns or that are owned by roles granted to it
-- (this is why custom roles should roll up to SYSADMIN)
Use USERADMIN to create a small role hierarchy. Two roles, one granted to the other.
USE ROLE USERADMIN;
CREATE ROLE jr_analyst;
CREATE ROLE sr_analyst;
-- jr_analyst rolls up to sr_analyst (privilege inheritance)
GRANT ROLE jr_analyst TO ROLE sr_analyst;
-- sr_analyst rolls up to SYSADMIN (best-practice anchor)
USE ROLE SECURITYADMIN;
GRANT ROLE sr_analyst TO ROLE SYSADMIN;
-- Give yourself both roles so we can switch between them
GRANT ROLE jr_analyst TO USER IDENTIFIER(CURRENT_USER());
GRANT ROLE sr_analyst TO USER IDENTIFIER(CURRENT_USER());
sr_analyst or jr_analyst. This is the textbook custom-role pattern from Micro-Concept 4.Prove the network-policy SECURITYADMIN rule.
USE ROLE SYSADMIN;
-- Should FAIL: SYSADMIN doesn't have CREATE NETWORK POLICY
CREATE NETWORK POLICY day19_test_np
ALLOWED_IP_LIST = ('0.0.0.0/0');
-- Expected error: Insufficient privileges to operate on account
USE ROLE SECURITYADMIN;
-- Should SUCCEED: SECURITYADMIN has the privilege
CREATE NETWORK POLICY day19_test_np
ALLOWED_IP_LIST = ('0.0.0.0/0');
-- Clean up
DROP NETWORK POLICY IF EXISTS day19_test_np;
Activate secondary roles.
-- Set jr_analyst as the primary role
USE ROLE jr_analyst;
-- Inspect the current state
SELECT CURRENT_ROLE() AS primary_role,
CURRENT_SECONDARY_ROLES() AS secondary_roles;
-- Note the "value" key: either NONE or ALL depending on your account default
-- Explicitly activate every granted role as secondary
USE SECONDARY ROLES ALL;
SELECT CURRENT_ROLE() AS primary_role,
CURRENT_SECONDARY_ROLES() AS secondary_roles;
-- value = "ALL"; the "roles" key lists every directly-granted role
-- Disable secondary roles
USE SECONDARY ROLES NONE;
SELECT CURRENT_SECONDARY_ROLES();
-- value = "NONE"; primary role alone authorizes SQL actions
jr_analyst regardless of secondary-role state. Secondary roles only change which privileges authorise queries. They do not change which role would own a new object.Prove that only the primary role creates objects.
USE ROLE jr_analyst;
USE SECONDARY ROLES ALL;
-- jr_analyst has no CREATE DATABASE privilege; sr_analyst (granted as secondary) doesn't either
-- This will fail regardless of secondary roles
CREATE DATABASE day19_test_db;
-- Expected error: Insufficient privileges
-- But if you switch the primary role to one that DOES have CREATE DATABASE:
USE ROLE SYSADMIN;
USE SECONDARY ROLES ALL;
CREATE DATABASE day19_test_db;
-- Succeeds. day19_test_db is owned by SYSADMIN (the primary role), not by any secondary role.
SHOW DATABASES LIKE 'day19_test_db';
-- Check the "owner" column — it's SYSADMIN, not the secondaries.
USE SECONDARY ROLES ALL, ownership tracks CURRENT_ROLE() and nothing else. This is the most-tested secondary-role nuance on the exam — every cohort I train guesses wrong on it the first time.Cleanup.
USE ROLE ACCOUNTADMIN;
DROP DATABASE IF EXISTS day19_test_db;
DROP ROLE IF EXISTS jr_analyst;
DROP ROLE IF EXISTS sr_analyst;
-- lab_xs warehouse stays; day10_orders stays.
Snowflake Documentation
Official docs for today’s topics.
External References
Role hierarchy and context functions.
Practice Questions
Options:
A. ACCOUNTADMIN
B. SECURITYADMIN
C. SYSADMIN
D. USERADMIN
Why B: The Snowflake docs on CREATE NETWORK POLICY state explicitly that only SECURITYADMIN or higher, or a role with the global CREATE NETWORK POLICY privilege, can create network policies. SECURITYADMIN is the documented best-practice answer because security and access-management tasks are its dedicated scope — that is separation of duties working as designed.
Why not A: ACCOUNTADMIN can do it because it inherits SECURITYADMIN, but Snowflake recommends keeping ACCOUNTADMIN reserved for a small number of trusted users and using the more specific role for routine work. The exam consistently rewards the least-privilege choice.
Why not C: SYSADMIN owns warehouses and databases. Network policy creation sits outside that scope. This is the trap distractor — the word “network” sounds infrastructural so the brain reaches for SYSADMIN.
Why not D: USERADMIN creates users and roles. It does not hold the privilege to create network policies.
Options:
A. ACCOUNTADMIN
B. ORGADMIN
C. SECURITYADMIN
D. SYSADMIN
Why B: ORGADMIN is the system role scoped to the organisation layer above accounts — creating accounts, viewing cross-account usage, managing the organisation as a unit. It sits separately from the standard role hierarchy (it is not above or below ACCOUNTADMIN, it is alongside it). Snowflake is transitioning newer organisation-account configurations to GLOBALORGADMIN, but ORGADMIN remains the C03-canonical answer.
Why not A: ACCOUNTADMIN is the top of the per-account hierarchy. It manages a single account, not the organisation that contains it. This is the most-common wrong answer because the names sound similar.
Why not C: SECURITYADMIN handles grants and security policies within an account.
Why not D: SYSADMIN handles warehouses and databases within an account.
Options:
A. Objects created in this session will be owned by all four roles jointly.
B. Objects created in this session are owned by data_engineer_r; the secondary roles only authorize query and DML privileges.
C. CURRENT_ROLE() will return a JSON list of all four roles.
D. Secondary roles must be re-activated for each SQL statement; they don’t persist across statements.
Why B: Object creation is always authorised by the primary role, and ownership goes to it. Secondary roles contribute extra privileges for queries and DML but cannot create or own. This is the most-tested fact about secondary roles in the entire exam — every cohort I train misses it on the first attempt.
Why not A: Joint ownership does not exist in Snowflake’s model. Every object has exactly one owning role.
Why not C: CURRENT_ROLE() returns the primary role’s name as a single string. The secondary roles surface through CURRENT_SECONDARY_ROLES() as a separate JSON output.
Why not D: Secondary roles persist for the session. Snowflake does re-evaluate the role set on every statement, so a fresh grant or revoke takes effect on the next statement — but that is dynamic evaluation, not constant re-activation.
Options:
A. ACCOUNTADMIN
B. SECURITYADMIN
C. SYSADMIN
D. PUBLIC
Why C: Snowflake’s documented best practice is to grant every custom account role to SYSADMIN. SYSADMIN then inherits the privileges of every custom role and can manage the warehouses, databases, and other objects they create — without anyone touching ACCOUNTADMIN for routine work. This is what Micro-Concept 3 is really about: ACCOUNTADMIN is not automatically a superuser, so the hierarchy has to be wired explicitly.
Why not A: ACCOUNTADMIN should be used sparingly. Wiring custom roles directly under it encourages over-use of the top role and breaks least-privilege design.
Why not B: SECURITYADMIN manages grants and security policies. It is not the operational owner of warehouses and databases — that is SYSADMIN’s lane.
Why not D: Granting custom roles to PUBLIC would expose them to every user in the account. That is the exact opposite of what role design exists to achieve.
Options:
A. Every user is automatically granted the PUBLIC role; it does not need to be granted explicitly.
B. PUBLIC is owned by SYSADMIN and inherits from ACCOUNTADMIN.
C. Every role in the account inherits PUBLIC; anything granted to PUBLIC is accessible to all users.
D. PUBLIC can be dropped if it is no longer needed.
E. PUBLIC holds the MANAGE GRANTS privilege by default.
Why A: PUBLIC is a built-in pseudo-role. Every user gets it automatically the moment they exist — no explicit GRANT ROLE PUBLIC is required or possible.
Why C: Every role in the account inherits PUBLIC, so anything granted to PUBLIC flows to every role and every user. That is why PUBLIC grants are both powerful and dangerous — treat any privilege handed to PUBLIC as “everyone in the account has it.” I have seen this exact mistake leak SELECT on a sensitive table to an entire organisation more than once.
Why not B: PUBLIC is not owned by SYSADMIN. It is a system pseudo-role at the bottom of the hierarchy. Every role inherits PUBLIC, not the reverse.
Why not D: PUBLIC cannot be dropped. It is foundational to the role system.
Why not E: MANAGE GRANTS lives on SECURITYADMIN, not PUBLIC. Re-read Micro-Concept 1 if missed.
Today you learned: The six system-defined roles — ORGADMIN (organisation-level, separate from the standard hierarchy, transitioning to GLOBALORGADMIN), ACCOUNTADMIN (top of the standard hierarchy, NOT a superuser), SECURITYADMIN (MANAGE GRANTS plus network policies), USERADMIN (creates users and roles), SYSADMIN (warehouses and databases, recommended custom-role parent), and PUBLIC (automatic for every user, inherited by every role). The most-tested trap of the lot is “which role creates network policies” — SECURITYADMIN, not SYSADMIN. The custom-role pattern is USERADMIN creates → SECURITYADMIN grants → GRANT ROLE custom_r TO ROLE SYSADMIN → grant to the user. Secondary roles activate multiple roles in one session via USE SECONDARY ROLES ALL | NONE | role1, role2, but only the primary role can create objects, and the default for new users is now 'ALL' (changed from NULL in 2024 by BCR-1692). Inspect with CURRENT_ROLE() and CURRENT_SECONDARY_ROLES().
Key takeaway: The role layer is where most Domain 2 questions live. If you can pair each system role with its one defining responsibility (org operations / billing-and-top / grants-and-network / users-and-roles / warehouses-and-DBs / everyone), and you remember that secondary roles never create objects, you will collect every role-related mark on the exam.
Tomorrow (Day 20) — Authentication: MFA, SSO, OAuth, Key-Pair. We close sub-objective 2.1 with how users actually log in. Four authentication methods to recognise: MFA (multi-factor, now mandatory for ACCOUNTADMIN), SSO/SAML (federated identity via an IdP), OAuth (token-based, for Snowpark and third-party apps), and Key-Pair (no password, standard for service accounts). Each carries its own exam-tested constraint, and the recent C03 emphasis on key-pair auth replacing password-based service-account access is worth paying close attention to.