Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To give someone access in a SQL Server database, grant the specific permission they need—ideally to a database role, then add the user to that role. For example, this grants read access to objects in a dedicated Reporting schema:

USE SalesDb;
GO

CREATE ROLE ReportingRole;
GRANT SELECT ON SCHEMA::Reporting TO ReportingRole;
ALTER ROLE ReportingRole ADD MEMBER ReportingUser;
GO

ReportingUser must already exist as a user in SalesDb. Granting a login access to the server is not the same as authorizing it to read or change data in a database.

Understand logins, users, roles, and permissions

A login authenticates a person or service at the server level. A database user is the principal SQL Server authorizes inside a particular database. A database role groups users who need similar access, and permissions are assigned to users or roles on protected resources called securables.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Login or contained identity
          ↓
     Database user
          ↓
   Database role membership
          ↓
Permission on database, schema, object, or column

This is the usual model on boxed SQL Server. Azure SQL Database also supports contained database users, including Microsoft Entra identities, and its server-level access model differs from a SQL Server instance. Check the applicable [Microsoft guidance on logins and database users](https://learn.microsoft.com/en-us/azure/azure-sql/database/logins-create-manage?view=azuresql) before applying server-login examples to Azure.

Permissions can apply at server, database, schema, object, or column scope. A broader scope affects more resources. Choose the narrowest scope that meets the need; see Microsoft’s overview of SQL Server securables and Database Engine permissions.

Choose the permission and scope

Need Typical permission Example scope
Read rows SELECT A view, table, or reporting schema
Add rows INSERT A particular table or application schema
Change rows UPDATE A particular table; consider column scope if suitable
Delete rows DELETE A particular table
Run a stored procedure EXECUTE A procedure or API schema
See object definitions VIEW DEFINITION An object or database
Create tables CREATE TABLE Database

The same permission can have very different reach depending on scope. SELECT on one object is narrower than SELECT on a schema, which is narrower than a database-wide reader role. Avoid granting permissions simply because a role name sounds convenient.

Create or identify the database user

First connect to the target database and confirm whether the user already exists. On SQL Server, an existing login can be mapped to a database user like this:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
USE SalesDb;
GO

CREATE USER AppUser FOR LOGIN AppLogin;
GO

For a Windows account or group, use its exact domain-qualified name:

CREATE USER [CONTOSOSales Analysts]
FOR LOGIN [CONTOSOSales Analysts];
GO

A contained SQL user is created inside the database rather than mapped to a server login. Syntax and supported identity types vary by SQL Server and Azure service; for example, Azure SQL Database supports database-contained users. Do not copy a contained-user command into an environment without confirming it supports that authentication method. A user-creation example for a contained SQL user is:

CREATE USER ReportingUser
WITH PASSWORD = 'Use-A-Strong-Secret-Here';

Use a securely managed secret rather than a literal production password in a script or source repository. If you need to create a SQL Server login, that is a separate server-level operation; it does not itself grant access to database objects.

Recommended approach: grant to a custom role

Roles are easier to review and maintain than a collection of individual grants. This example gives members read permission on the Reporting schema:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
USE SalesDb;
GO

CREATE ROLE ReportingRole;
GO

GRANT SELECT ON SCHEMA::Reporting TO ReportingRole;
GO

ALTER ROLE ReportingRole ADD MEMBER ReportingUser;
GO

The role must exist before users can be added to it, and the user and role must be in the target database. Use ALTER ROLE ... ADD MEMBER for new scripts rather than the older sp_addrolemember procedure. A schema grant applies to the schema’s objects, so review that schema’s contents—including objects added later—to ensure they share the same access boundary. See Microsoft’s schema permission guidance.

To grant access to only one table, use an object-level permission instead:

GRANT SELECT
ON OBJECT::dbo.Customers
TO ReportingRole;

Common T-SQL grants

Grant read or write access to one object

GRANT SELECT
ON OBJECT::dbo.Customers
TO ReportingRole;

GRANT INSERT, UPDATE
ON OBJECT::dbo.CustomerNotes
TO CustomerServiceRole;

Use the actual schema-qualified object name. A table named Customers is not necessarily dbo.Customers.

Grant permission on a view or procedure

GRANT SELECT
ON OBJECT::dbo.CustomerSummary
TO ReportingRole;

GRANT EXECUTE
ON OBJECT::dbo.usp_GetCustomer
TO AppRole;

For an application, granting execution on a deliberately designed set of procedures can avoid direct table permissions. It is not automatically safe: review what the procedures return, any dynamic SQL they execute, their ownership and execution context, and their input handling.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Grant permissions on a schema

GRANT SELECT
ON SCHEMA::Reporting
TO ReportingRole;

GRANT EXECUTE
ON SCHEMA::Api
TO AppRole;

Schema scope is useful when its objects form a consistent security boundary. It can also expose future objects placed in that schema, so review the schema design and deployment practices.

Grant at database scope

Database-level permissions are broader and should be chosen deliberately. For example, a developer role may need to create tables, or a role may need to view definitions throughout the database:

GRANT CREATE TABLE TO DeveloperRole;

GRANT VIEW DEFINITION
ON DATABASE::SalesDb
TO DeveloperRole;

Do not use GRANT ALL as shorthand for full access. Microsoft documents ALL as deprecated, and it does not mean every possible permission. Use named permissions and the appropriate securable scope. Refer to the current GRANT documentation for syntax and supported permissions.

When fixed database roles are appropriate

Fixed roles are convenient for simple cases, but can be much broader than a production task requires:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • db_datareader can read all user tables and views in the database.
  • db_datawriter can insert, update, and delete data across user tables.
  • db_owner has full control of the database.
  • db_ddladmin is intended for database definition tasks, not routine data access.

For example, membership is added with:

ALTER ROLE db_datareader ADD MEMBER ReportingUser;

This can be reasonable when database-wide access is genuinely intended. It is not equivalent to access to a curated reporting area. For narrower production access, create a custom role and grant only the needed permissions. Microsoft notes that fixed roles may suit simple setups, while more granular permissions are preferable in many scenarios; see authorization guidance.

Grant column-level access carefully

For supported permissions, SQL Server can limit a grant to selected columns:

GRANT SELECT (CustomerId, DisplayName, Region)
ON OBJECT::dbo.Customers
TO LimitedReportingRole;

Column grants are useful in specific cases, but should not be treated as a universal data-isolation mechanism. SQL Server documents a backward-compatibility exception in which a table-level DENY does not override a column-level GRANT. Test the exact effective permissions and query paths. See object and column permission details.

Use SSMS to grant permissions

In SQL Server Management Studio (SSMS), the path varies by securable and version, but for a table, view, or procedure the general steps are:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Connect to the instance and expand Databases in Object Explorer.
  2. Expand the target database and locate the object.
  3. Right-click the object and select Properties.
  4. Open Permissions, then use Search to add the database user or role.
  5. Select the principal and choose the appropriate explicit permission state—Grant, Grant with Grant, or Deny—then apply the change.

For a stored procedure, the documented path is under Programmability → Stored Procedures, then right-click the procedure, choose Properties → Permissions. To manage role membership, expand the database’s Security → Roles → Database Roles, open the role’s properties, and use its Members page. Exact labels can vary. See Microsoft’s SSMS permission steps.

The SSMS grid shows explicit permissions, not necessarily every path by which access is inherited. A user may also receive access through roles, Windows groups, broader grants, ownership, or execution context. Use queries and test under the intended identity as well.

Verify the permission and identity

Check the execution context first if an application or user reports unexpected access:

SELECT
    SUSER_SNAME() AS LoginName,
    ORIGINAL_LOGIN() AS OriginalLogin,
    USER_NAME() AS DatabaseUser,
    DB_NAME() AS DatabaseName;

List database users and their authentication type:

SELECT
    name,
    type_desc,
    authentication_type_desc,
    default_schema_name
FROM sys.database_principals
WHERE type NOT IN ('R', 'X')
ORDER BY name;

Review role membership:

SELECT
    role_name = roles.name,
    member_name = members.name
FROM sys.database_role_members AS drm
JOIN sys.database_principals AS roles
    ON roles.principal_id = drm.role_principal_id
JOIN sys.database_principals AS members
    ON members.principal_id = drm.member_principal_id
ORDER BY roles.name, members.name;

Review explicit permissions recorded in the database:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
SELECT
    grantee.name AS grantee_name,
    grantee.type_desc AS grantee_type,
    dp.state_desc,
    dp.permission_name,
    dp.class_desc,
    major_name =
        CASE dp.class
            WHEN 0 THEN DB_NAME()
            WHEN 1 THEN OBJECT_SCHEMA_NAME(dp.major_id)
                         + N'.'
                         + OBJECT_NAME(dp.major_id)
            WHEN 3 THEN SCHEMA_NAME(dp.major_id)
        END
FROM sys.database_permissions AS dp
JOIN sys.database_principals AS grantee
    ON grantee.principal_id = dp.grantee_principal_id
ORDER BY grantee.name, dp.class_desc, dp.permission_name;

state_desc can show GRANT, GRANT_WITH_GRANT_OPTION, or DENY. A revoked permission is generally represented by the absence of an explicit permission row, not a positive REVOKE entry. These catalog results show explicit configuration; they are not, by themselves, a complete explanation of effective access.

Check a named permission in the current execution context with HAS_PERMS_BY_NAME:

SELECT HAS_PERMS_BY_NAME(
    'dbo.Customers', 'OBJECT', 'SELECT'
) AS CanSelectCustomers;

You can also inspect permissions available to the current user:

SELECT *
FROM sys.fn_my_permissions(NULL, 'DATABASE');

SELECT *
FROM sys.fn_my_permissions('dbo.Customers', 'OBJECT');

To test as a database user, use impersonation where you have the required authority:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
EXECUTE AS USER = 'ReportingUser';

SELECT
    USER_NAME() AS DatabaseUser,
    DB_NAME() AS DatabaseName,
    HAS_PERMS_BY_NAME(
        'Reporting.Customers', 'OBJECT', 'SELECT'
    ) AS CanSelectCustomers;

REVERT;

Run the test in the target database. HAS_PERMS_BY_NAME checks a named permission and scope; it does not replace checking role membership, broader permissions, or the application’s actual connection identity.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Change or remove access

Remove a user from a custom role when they should no longer inherit its permissions:

ALTER ROLE ReportingRole DROP MEMBER ReportingUser;

Remove an explicit grant at its scope with REVOKE:

REVOKE SELECT
ON SCHEMA::Reporting
FROM ReportingRole;

REVOKE removes an explicit grant or deny at the specified scope; it does not cancel access the user still receives through another role, a Windows group, a broader grant, or another valid permission path.

DENY explicitly blocks a permission and generally takes precedence over a grant at the same or a lower scope. However, SQL Server has documented exceptions, including the column-level behavior above. Prefer a clean least-privilege role design over using DENY to patch an overly broad grant. See Microsoft’s GRANT, DENY, and REVOKE reference.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

WITH GRANT OPTION lets the recipient grant the permission to other principals. Use it only when the recipient is meant to administer access; it expands the permission-management boundary and complicates review.

Troubleshoot common permission failures

“The user exists, but cannot connect”

  • Confirm the login, contained identity, or other authentication method is available and enabled.
  • Confirm you are connecting to the intended server and database, and that the user is created in the right database.
  • Check for a database-level DENY CONNECT or an unavailable database.
  • Confirm the platform and identity syntax match: Azure SQL Database, Managed Instance, and boxed SQL Server do not have identical server-level models.

On SQL Server 2022 and later, the ##MS_DatabaseConnector## server role is relevant to connection access across databases; it is distinct from permission to read or modify database objects. See Microsoft’s server-level role documentation.

“SELECT permission was denied”

  1. Check DB_NAME() and the fully qualified object name.
  2. Confirm the grant targets the database user or a role the user actually belongs to—not just a server login.
  3. Check explicit permissions and role membership, including for Windows groups.
  4. Look for a DENY at a relevant scope.
  5. Confirm the application is using the identity you expect.
  6. If access is through a view, procedure, synonym, or cross-database reference, inspect that full path and its execution context.

Cross-database access

A grant in one database does not automatically create a user or grant permission in another. The principal generally needs an appropriate identity and permissions in each database it accesses. Verify the security design for the particular platform rather than assuming that a server login alone authorizes database access.

Windows groups

Granting to a managed Windows group can simplify onboarding and offboarding. You can create a database user for the group, add it to a database role, and grant permissions to the role. If a group membership change appears not to take effect, verify the identity token and connection context with the identity administrator; cached authentication context or nested group membership may affect what the session presents.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Orphaned users after a restore or migration

A database user mapped to an instance login by security identifier (SID) can lose that mapping after restore or migration if the corresponding login differs. This diagnostic finds instance-authenticated database users with no matching server principal SID:

SELECT
    dp.name AS DatabaseUser,
    dp.type_desc,
    sp.name AS LoginName
FROM sys.database_principals AS dp
LEFT JOIN sys.server_principals AS sp
    ON dp.sid = sp.sid
WHERE dp.authentication_type_desc = 'INSTANCE'
  AND dp.name NOT IN ('dbo', 'guest', 'INFORMATION_SCHEMA', 'sys');

Interpret results before making changes: contained users do not use the same login mapping, and the correct repair depends on whether the intended login exists and on the SQL Server or Azure service. Correct the mapping to the intended login rather than creating duplicate users blindly.

Ownership chaining and indirect access

Ownership chaining can let a user execute a procedure or access an object through another object without a direct grant on every underlying object. This can support a controlled application interface, but changes to ownership, schema permissions, or dynamic SQL can alter the security boundary. In particular, do not grant ALTER on a schema merely because someone needs to read its objects; schema alteration can have broader consequences. Review the schema permission implications.

Keep database access least-privilege

  • Start from the action needed, then grant the narrowest permission and scope that supports it.
  • Prefer custom roles for repeatable access, and grant to managed groups where that fits your identity model.
  • Use object grants for a small set of objects or a dedicated schema when objects share a security boundary.
  • Reserve db_owner, db_securityadmin, and permission-administration rights for people who genuinely need them.
  • Avoid broad roles, GRANT ALL, and unnecessary WITH GRANT OPTION.
  • Test with the application’s actual identity and database, not only an administrator session.
  • Review permissions after deployments, restores, and changes to schema contents or role membership.

For a concise reference to permission hierarchy and syntax, use the current Microsoft documentation for permission hierarchy and GRANT.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.