ChatGPT解决这个技术问题 Extra ChatGPT

The server principal is not able to access the database under the current security context in SQL Server MS 2012

I am trying to access my hosting server’s database through SQL Server Management Studio, everything till login is fine but when I use the command use myDatabase it gives me this error:

The server principal "****" is not able to access the database "****" under the current security context.

I searched over and the hosting service providers has listed this fix for the problem.

But this is not working for me probably because it's for SQL Server Management Studio 2008 however I am using SQL Server Management Studio 2012.

Can this be a problem? And if yes than can anyone tell me its alternative in SSMS 2012?

'Hosting service providers'? Are we talking dedicated or shared? If it's a shared hosting server I highly recommend contacting your hosting provider for assistance. SQL in a shared hosting environment is notoriously buggy and problematic. It has nothing to do with the product but the policies the hosting providers apply to the server(s). Every hosting company has their own way to leverage SQL or so it seems.

S
Scott

Check to see if your user is mapped to the DB you are trying to log into.


@Graham Either use SQL Server Management Studio to check the User or see this answer: stackoverflow.com/a/9356725/804773
I would suggest to look for triggers, that was the reason I received this message, there was a trigger doing some stuff in another database where my user was not authorized.
I hit the OP's error and tanks to this answer, I figured out I just had a stupid typo in the Database Name in my connection string connecting to Azure SQL Database. If your Database Name is correct, you don't need access to Master. If it's wrong, then (in my case) I think Entity Framework (6.1.3) is trying to be extra smart by connecting to Master for some additional information (although that could just be unrelated to EF - I'm not sure). But my solution was to make sure my connectionstring was correct. I expected a very different error for a bad database name. :-/
To add onto @DanielV's comment, also check Stored Procedures for any hardcoded database names. Fixed it in my case (about 20 stored procedures had to be altered).
@scott It is mapped to.
A
Anonymous

We had the same error deploying a report to SSRS in our PROD environment. It was found the problem could even be reproduced with a “use ” statement. The solution was to re-sync the user's GUID account reference with the database in question (i.e., using "sp_change_users_login" like you would after restoring a db). A stock (cursor driven) script to re-sync all accounts is attached:

USE <your database>
GO

-------- Reset SQL user account guids ---------------------
DECLARE @UserName nvarchar(255) 
DECLARE orphanuser_cur cursor for 
      SELECT UserName = su.name 
      FROM sysusers su
      JOIN sys.server_principals sp ON sp.name = su.name
      WHERE issqluser = 1 AND
            (su.sid IS NOT NULL AND su.sid <> 0x0) AND
            suser_sname(su.sid) is null 
      ORDER BY su.name 

OPEN orphanuser_cur 
FETCH NEXT FROM orphanuser_cur INTO @UserName 

WHILE (@@fetch_status = 0)
BEGIN 
--PRINT @UserName + ' user name being resynced' 
exec sp_change_users_login 'Update_one', @UserName, @UserName 
FETCH NEXT FROM orphanuser_cur INTO @UserName 
END 

CLOSE orphanuser_cur 
DEALLOCATE orphanuser_cur

Worked for me Thank you. I had copied a database with a SQL server authentication to my test server and it was inaccessible. Now it is
If the User exists in the database but fails to persist a mapping to the Login, deleting said User via SSMS Object Explorer then remapping the Login worked for me. Otherwise, I suspect the solution proposed above would need to be taken.
T
Tobias J

SQL Logins are defined at the server level, and must be mapped to Users in specific databases.

In SSMS object explorer, under the server you want to modify, expand Security > Logins, then double-click the appropriate login entry. This will bring up the "Login Properties" dialog.

Select User Mapping, which will show all databases on the server. Those which already have a user mapped to that login will have have the "Map" checkbox selected. From here you can select additional databases (and be sure to select which roles in each database that user should belong to), then click OK to add the mappings.

Note that, while it's common practice to name the Users the same as the Login to avoid confusion, they don't have to match and you can name the User whatever you'd like.

https://i.stack.imgur.com/rv35R.png

These mappings can become disconnected after a restore or similar operation. In this case, the user may still exist in the database but is not actually mapped to a login. If that happens, you can run the following to restore the login:

USE {database};
ALTER USER {user} WITH login = {login}

You can also delete the DB user and recreate it from the Login Properties dialog, but any role memberships or other settings would need to be recreated.


Your comment should be the accepted answer. It clearly describes: - SQL Logins are at the Server level - SQL Users are at the Db level - Map the login to the user Missing action item
Great answer. This is exactly what I needed. Thank you!
Do note, if you connect against an Azure SQL Database, you cannot access this window. See also: stackoverflow.com/questions/52083296/…
P
Phil Ringsmuth

I spent quite a while wrestling with this problem and then I realized I was making a simple mistake in the fact that I had forgotten which particular database I was targeting my connection to. I was using the standard SQL Server connection window to enter the credentials:

https://i.stack.imgur.com/ezSbf.jpg

I had to check the Connection Properties tab to verify that I was choosing the correct database to connect to. I had accidentally left the Connect to database option here set to a selection from a previous session. This is why I was unable to connect to the database I thought I was trying to connect to.

https://i.stack.imgur.com/XRasS.jpg

Note that you need to click the Options >> button in order for the Connection Properties and other tabs to show up.


This worked for me, as the user I was logging in with only had access to a particular database. Thanks!
a
azak

This worked for me:

use <Database>
EXEC  sp_change_users_login @Action='update_one', @UserNamePattern='<userLogin>',@LoginName='<userLogin>';

The problem can be visualized with:

SELECT sid FROM sys.sysusers WHERE name = '<userLogin>'
SELECT sid FROM sys.syslogins WHERE name = '<userLogin>';

This fixed it for me. Thanks ! "The problem can be visualized with" -> If they return a different hash, there is a problem and the query above will sync them.
J
Joshua Yeidel

In my case, the message was caused by a synonym which inadvertently included the database name in the "object name". When I restored the database under a new name, the synonym still pointed to the old DB name. Since the user did not have permissions in the old DB, the message appeared. To fix, I dropped and recreated the synonym without qualifying the object name with the database name:

    USE [new_db]
GO

/****** Object:  Synonym [dbo].[synTable]    Script Date: 10/15/2015 9:45:01 AM ******/
DROP SYNONYM [dbo].[synTable]
GO

/****** Object:  Synonym [dbo].[synTable]    Script Date: 10/15/2015 9:45:01 AM ******/
CREATE SYNONYM [dbo].[synTable] FOR [dbo].[tTheRealTable]
GO

S
Salim Gangji

I believe you might be missing a "Grant Connect To" statement when you created the database user.

Below is the complete snippet you will need to create both a login against the SQL Server DBMS as well as a user against the database

USE [master]
GO

CREATE LOGIN [SqlServerLogin] WITH PASSWORD=N'Passwordxyz', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=ON
GO

USE [myDatabase]
GO

CREATE USER [DatabaseUser] FOR LOGIN [SqlServerLogin] WITH DEFAULT_SCHEMA=[mySchema]
GO

GRANT CONNECT TO [DatabaseUser]
GO

-- the role membership below will allow you to run a test "select" query against the tables in your database
ALTER ROLE [db_datareader] ADD MEMBER [DatabaseUser]
GO

D
Danny C

None of the excellent answers before this one resolved my fringe case issue. In my case, an "execute as user" statement preceded a call to execute a stored procedure, but that procedure read from a table in a different DB. Even though the user was a sysadmin, the sproc was failing for lack of access to the second database "under the current security context." This was working in production but failing in our development environment. I saw that in production, trustworthy was set to "on" in the initial database, but off on that database in development. I read that when restoring a database (as we restore production DBs to our dev environment from time to time) has the effect of turning trustworthy off. Setting it "on" in dev allowed the user read access to the second database.


c
crokusek

We had the same error even though the user was properly mapped to the login.

After trying to delete the user it was discovered that a few SPs contained "with execute as" that user.

The issue was solved by dropping those SPs, dropping the user, recreating the user linked to login, and recreating the SPs.

Possibly it got in this state from restoring from backup (during a time when the related login didn't exist) or bulk schema syncing (if its possible to create an SP with execute as even though the user doesn't exist. Could also have been related to this answer.


Can you elaborate on what you mean by SPs?
Stored Procedure. When creating an SP (create proc xxx ...), there is an optional clause "with execute as " that specifies that the SP will run as if that user had run it instead of the currently logged in user.
A
Alan

I encountered the same error while using Server Management Objects (SMO) in vb.net (I'm sure it's the same in C#)

Techie Joe's comment on the initial post was a useful warning that in shared hosting a lot of additional things are going on. It took a little time to figure out, but the code below shows how one has to be very specific in the way they access SQL databases. The 'server principal...' error seemed to show up whenever the SMO calls were not precisely specific in the shared hosting environment.

This first section of code was against a local SQL Express server and relied on simple Windows Authentication. All the code used in these samples are based on the SMO tutorial by Robert Kanasz in this Code Project website article:

  Dim conn2 = New ServerConnection()
  conn2.ServerInstance = "<local pc name>\SQLEXPRESS"
  Try
    Dim testConnection As New Server(conn2)
    Debug.WriteLine("Server: " + testConnection.Name)
    Debug.WriteLine("Edition: " + testConnection.Information.Edition)
    Debug.WriteLine(" ")

    For Each db2 As Database In testConnection.Databases
      Debug.Write(db2.Name & " - ")
      For Each fg As FileGroup In db2.FileGroups
        Debug.Write(fg.Name & " - ")
        For Each df As DataFile In fg.Files
          Debug.WriteLine(df.Name + " - " + df.FileName)
        Next
      Next
    Next
    conn2.Disconnect()

  Catch err As Exception
    Debug.WriteLine(err.Message)
  End Try

The code above finds the .mdf files for every database on the local SQLEXPRESS server just fine because authentication is handled by Windows and it is broad across all the databases.

In the following code there are 2 sections iterating for the .mdf files. In this case only the first iteration looking for a filegroup works, and it only finds a single file because the connection is to only a single database in the shared hosting environment.

The second iteration, which is a copy of the iteration that worked above, chokes immediately because the way it is written it tries to access the 1st database in the shared environment, which is not the one to which the User ID/Password apply, so the SQL server returns an authorization error in the form of the 'server principal...' error.

Dim sqlConnection1 As New System.Data.SqlClient.SqlConnection
sqlConnection1.ConnectionString = "connection string with User ID/Password to a specific database in a shared hosting system. This string will likely also include the Data Source and Initial Catalog parameters"
Dim conn1 As New ServerConnection(sqlConnection1)
Try
  Dim testConnection As New Server(conn1)
  Debug.WriteLine("Server: " + testConnection.Name)
  Debug.WriteLine("Edition: " + testConnection.Information.Edition)
  Debug.WriteLine(" ")

  Dim db2 = testConnection.Databases("the name of the database to which the User ID/Password in the connection string applies")
  For Each fg As FileGroup In db2.FileGroups
    Debug.Write(fg.Name & " - ")
    For Each df As DataFile In fg.Files
      Debug.WriteLine(df.Name + " - " + df.FileName)
    Next
  Next

  For Each db3 As Database In testConnection.Databases
    Debug.Write(db3.Name & " - ")
    For Each fg As FileGroup In db3.FileGroups
      Debug.Write(fg.Name & " - ")
      For Each df As DataFile In fg.Files
        Debug.WriteLine(df.Name + " - " + df.FileName)
      Next
    Next
  Next

  conn1.Disconnect()

Catch err As Exception
  Debug.WriteLine(err.Message)
End Try

In that second iteration loop, the code compiles fine, but because SMO wasn't setup to access precisely the correct database with the precise syntax, that attempt fails.

As I'm just learning SMO I thought other newbies might appreciate knowing there's also a more simple explanation for this error - we just coded it wrong.


M
Martin Bjel

On SQL 2017 - Database A has synonyms to Database B. User can connect to database A and has exec rights to an sp (on A) that refers to the synonyms that point to B. User was set up with connect access B. Only when granting CONNECT to the public group to database B did the sp on A work. I don't recall this working this way on 2012 as granting connect to the user only seemed to work.


M
Mathew Paxinos

I had this issue specific to the case of a USER WITHOUT LOGIN, after a backup and restore of the database to a different server the user lost it's connection with the database.

To resolve the issue we needed to ensure that the user was connected to the database.

GRANT CONNECT TO [DatabaseUser]
GO

This is similar to the answer given by Salim Gangji above but specific to the case of a USER WITHOUT LOGIN.


J
Jose Mozqueda

I use:

 DECLARE @sql VARCHAR(255)
   DECLARE @owner VARCHAR(255)

        WHILE EXISTS (SELECT DISTINCT S.name AS owner
               FROM sys.schemas s, sys.database_principals u
               WHERE s.principal_id = u.principal_id
               AND u.name NOT IN( 'dbo' ,'guest','sys','INFORMATION_SCHEMA')
               AND u.name NOT LIKE 'db_%')
        BEGIN 
         SET @owner = (SELECT DISTINCT TOP(1) s.name
                       FROM sys.schemas s, sys.database_principals u
                       WHERE s.principal_id = u.principal_id
                       AND u.name NOT IN( 'dbo' ,'guest','sys','INFORMATION_SCHEMA')
                       AND u.name NOT LIKE 'db_%') 
         SET @sql = 'ALTER AUTHORIZATION ON SCHEMA::' + @owner + ' TO dbo' 
         PRINT @sql   
         exec (@sql)  
        END 


    DECLARE @name varchar(500)
DECLARE @db varchar(100)= DB_NAME()
DECLARE @strQuery varchar(1000)='use '+ @db
DECLARE consec CURSOR FOR
select name from sys.sysusers WHERE hasdbaccess=1 and name not in ('dbo','guest') /*and name not like 'esfcoah%'*/ AND status=0
OPEN consec
FETCH NEXT FROM consec INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
    set @strQuery='use ['+@db+']'
    exec(@strQuery)
    if exists(select * from sys.schemas where name like @name)
    begin
        set @strQuery='DROP SCHEMA ['
        set @strQuery=@strQuery+@name+']'
        exec(@strQuery)
    end

    set @strQuery='DROP USER ['
    set @strQuery=@strQuery+@name+']'
    exec(@strQuery)

    set @strQuery='USE [master]'
    exec (@strQuery)

    if not exists(select * from sys.syslogins where name like @name)
    begin
        set @strQuery='CREATE LOGIN ['+@name+'] WITH PASSWORD=N''a'', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF'
        exec (@strQuery)
    end

    set @strQuery='use ['+@db+']'
    exec(@strQuery) 

    set @strQuery='CREATE USER ['+@name+'] FOR LOGIN ['+@name+']'
    exec(@strQuery) 

    set @strQuery='EXEC sp_addrolemember N''db_owner'', N'''+@name+''''
    exec(@strQuery)

FETCH NEXT FROM consec INTO @name
end
close consec
deallocate consec

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
S
Samurai21

This is because your server is not mapped with the desired database you want to access.

Following worked for me:

Go to Security folder in the server.

Double click it and go to Logins folder.

Find your user id and double-click it.

Login Properties window will open up.

In that go to User Mapping.

Tick all the Databases that you want to map with that Login.