Home » Securing SQL Server linked servers

Securing SQL Server linked servers

by Vlad Drumea
3 comments 16 minutes read

In this post I’ll address improper linked server configurations and their potential impact, as well as recommendations for securing SQL Server linked servers.

Linked servers are one of SQL Server’s features that can be very useful and versatile, but can also be pretty easy to incorrectly set up and improperly secure.

What’s a SQL Server linked server?

A linked server is a server-level object that is used to create a connection between two SQL Server instances or between a SQL Server instance and another RDBMS, that allows querying and command execution against a remote database.
A few examples of other RDBMSs to which linked server connections can be created:

  • Oracle
  • SAP Hana
  • MySQL
  • PostgreSQL

In this post I’ll only focus on the scenario where a linked server connection is established between two SQL Server instances.

How does authentication work in linked servers?

To properly understand the security implications of linked servers I’ll first go over how instance authentication in a linked server connection can be configured.

Mapping a login from instance A to a login on instance B.

This tells SQL Server that, when login A from instance A tries to access a resource from instance B through the linked server connection, it should use login B that exists on the remote instance (instance B).

Here’s an example from my test environment, where on the WINSRV2K22\SQL2022 instance I’ve created a linked server connection to the WINSRV2K22\SQL2019 instance.


In this case, if either SQL2022Login (a SQL login) or WinSrv2k22\WinSQL2022 (a login based on a Windows account), both of which exist only on the WINSRV2K22\SQL2022 instance, try to access a resource from WINSRV2K22\SQL2019 via the linked server connection, they will both interact with the remote instance as the SQL2019Login (a SQL login that only exists on WINSRV2K22\SQL2019) with the password saved in the Remote Password field.

Setting a login from instance A to interact with resources on instance B as itself.

This requires the existence of the same login with the same password (if it’s a SQL login) on both instances, otherwise it won’t work.

Using the same example from my test environment, when either of WinSrv2k22\WinSQLBoth (a login based on a Windows account) or SQLBothLogin (a SQL login) try to access a resource from WINSRV2K22\SQL2019 via the linked server connection they’ll do that directly as themselves since both logins exist on both instances.


What about logins not defined in the mapping?

This is where the seconds half of the Security page in the Linked Server Properties menu comes in.


This section specifies if and how the connection on the remote instance should be made for if any login that isn’t specified in the mapping section tries to access the remote instance through the linked server connection.

OptionExplanationRecommended option
Not be madeThis is the most restrictive option. If any login on the local instance tries to use the linked server connection, but isn’t defined in local login to remote login mapping section, it will simply encounter the following error message:

Msg 7416, Level 16, State 1, Line 7
Access to the remote server is denied because no login-mapping exists.
Yes, especially from a security standpoint.
Be made without using a security contextThis will result in an anonymous connection to be made in an attempt to login against the remote server and, in most cases, will result in the following error message:

Msg 7399, Level 16, State 1, Line 7
The OLE DB provider “MSOLEDBSQL” for linked server “WINSRV2K22\SQL2019” reported an error. Authentication failed.
Yes, since it’s really limited by default
Be made using the login’s current security contextThis acts just like the Impersonate option in the login mapping section, but doesn’t require you to specify the local login name.
It will just let any local login that also exists on the remote instance access the remote instance’s resources via the linked server connection.
Any logins that only exist on the local instance, but not on the remote instance, will still get the 7416 error message when trying to use the linked server connection.
It depends on whether you want all the users with logins on both instance A and B to be able to use the linked server connection.
Be made using this security contextChecking this option will enable the “Remote login” and “With password” fields found right under it.
That will basically act as a catch-all mapping for all the other logins not specified in the in local login to remote login mapping section.
This the most lax option and will result in every login on the local instance being able access the remote instance through the linked server connection, with the only limitation being the specified remote login’s level of permissions.
NOPE.
At best – all the logins on instance A get access to instance B and access data that some of them might not be allowed to.
At worst – they’ll all end up connecting as SA to instance B through the linked server.
Either way, I strongly recommend avoiding this option.

Setting up the demo environment

For this demo I’m using a Windows Server 2022 VM hosting 2 SQL Server instance, one 2022 and one 2019, although in this case SQL Server versions are not that important since linked server connections have the same general behavior since SQL Server 2008.

First step is to create 3 Windows accounts using PowerShell opened as Administrator.
Note, these are local Windows users since I’m not in an AD environment, in an AD environment you’d normally have domain accounts.


Now, in SQL Server, I create a few logins as follows:

  • Only on the WinSrv2k22\SQL2019 instance

  • Only on the WinSrv2k22\SQL2022 instance

  • On both instances

Now to create the linked server connection on the WinSrv2k22\SQL2022 instance.
I’ll go through both ways of creating the linked server connection, the GUI way and the T-SQL way.

Creating SQL Server linked servers using the GUI

In the General page I select the “SQL Server” radio button and fill in the name of the remote instance, which in this case is WinSrv2k22\SQL2019


Notice the highlighted message at the bottom of the window stating that:
“Server Type is either SQL Server or an OLE DB provider installed on the server. If SQL Server is
selected then the Linked Server name is also the network name of the server.”.

This means that the linked server object will have the same name as the remote instance WinSrv2k22\SQL2019, this can me changed later on if needed (and I’ll change it in order to avoid any potential confusion).

Up next is the Security page where I specify which local logins can connect as themselves to the remote instance (hint: it’s the ones with the Impersonate checkbox checked), and which local logins should map to the SQL2019Login login that exists on the remote instance.

I also check the “Not be made” radio button so that local logins not defined in the mapping section won’t be able to use the linked server connection.


On to the “Server Options” page where I set RPC (remote procedure call) and RPC Out to true because I want to be able to execute T-SQL, and have it return output, through the linked server connection, not just perform basic DML against some table(s).


Last thing left to do is to hit Ok in order to create the linked server connection.

Detour for potentially confusing error messages

But, when I press OK, out of nowhere:


Now, this is what I suspect can get people to press “No” and go back to the security page to add their login to the login mapping list.
Which isn’t really a bad thing, especially if they can use the impersonate option.

But they also might just go straight to checking either “Be made using the login’s current security context” or, the really bad option, “Be made using this security context”, and combine it with the sa credentials for the remote instance.
Which would lead to everyone who has any type of access on WinSrv2k22\SQL2022 ending up interacting as sa with the WinSrv2k22\SQL2019 instance via the linked server connection.

There’s even a StackOverflow question where the approved answer is resorting to the “Be made using this security context” option, but, luckily, not directly with the remote instance’s sa account.

There’s also some consulting company recommending the same thing on their blog, but I’m not linking the post here because of reasons.

This is one of those errors where reading the error message carefully (even a couple of times if needed) gives us a better understanding of what’s going on.

The first line starts with the linked server was created, which is good, but continues with “but failed a connection test”, which means that, even if it’s showing up in OE, it’s not working right, right?


Well, not really. Reading the rest of the error message reveals the reason of the connection test failure “access was denied because no login mapping exists”.

So what actually happened?

SQL Server did, successfully I might add, create the linked server connection exactly how I configured it, but, because I’m logged in as sa, and I haven’t defined any mapping or impersonation of the sa login from the local instance the sa or any other login on the WinSrv2k22\SQL2019 instance, when SQL Server tries to test the linked server connection it will do so as my current login which causes the above error message.

TL;DR: it’s ok, the linked server is created and works as intended

This can be easily tested by logging in as one of the logins that are defined in the linked server connection and doing a test.

SSMS result showing the outputs of the above queries

I’ve mentioned earlier that I want to rename the linked server connection to avoid confusion, and I can do this via the sp_serveroption system stored procedure:


Creating the SQL Server linked server via T-SQL

Note, you won’t get the 7416 error message when using T-SQL to create a linked server, because the linked server test is only done when creating it from the GUI.


Demoing a linked server connection

To test the linked server connection, I’ll run the following query logged in on WinSrv2k22\SQL2022 as different users.


First, a “baseline” using the sa account which just throws the same error that I got when creating the linked server connection.
Msg 7416, Level 16, State 1, Line 9
Access to the remote server is denied because no login-mapping exists.

SQL login with Impersonate checked


SQL login mapped to a remote SQL login


Login from Windows account mapped to a remote SQL login


Login from Windows account with Impersonate checked


How can a SQL Server linked server become a security risk?

There are two main ways in which I’ve seen linked servers between two SQL Server instances configured in such a way that ended up with a low privilege login from instance A running as SA or another high privilege account on instance B:

One or more low privilege local logins mapped to the remote instance’s sa login

To reproduce this scenario, I modify the two entries where local logins were mapped to low privilege remote logins so that they are now mapped to the remote instance’s SA login.


Running a simple test confirms that now every interaction made by either SQL2022Login or WinSrv2k22\WinSQL2022 to the remote instance via the linked server connection will be as SA.

SSMS result set showing that the local login is SQL2022Login, but it's interacting with the linked server instance as sa

This also means that with the help of the linked server connection and a bit of crafty T-SQL, either of those two user can create their own logins on SQL2019 and add said logins to the SysAdmin fixed server-level role.


Using the remote instance’s SA login as a catch-all

This is a worst case scenario because this results in anyone who has access to the WinSrv2k22\WinSQL2022 instance being able to interact with WinSrv2k22\WinSQL2019 as SA.

To recreate this I remove all the entries from the mappings section, select the “Be made using this security context” radio button and fill in the SA credentials for the WinSrv2k22\WinSQL2019 instance.


<sarcasm>The good news is that now I no longer get a 7416 error when saving the changes I’ve done to the linked server connection.</sarcasm>
The bad news is…

SSMS result set showing that the local login is SQL2022Login, but it's interacting with the linked server instance as sa
SSMS result set showing that the local login is WinSrv2k22\WinSQL2022, but it's interacting with the linked server instance as sa

Everyone from WinSrv2k22\WinSQL2022 gets to be sa on WinSrv2k22\WinSQL2019.

Bonus round – the most unfortunate setup I have ever ran into

This is probably the biggest failure in securing SQL Server linked servers I’ve ever seen.
I hope it’s a fairly rare set-up since I’ve only seen it a couple of times in real life and once in a CTF.

The first part of the story is pretty familiar: A linked server connection from instance A to instance B using the remote instance’s sa login as a catch-all.

But the twist her is that instance B, in turn, has a linked server connection back to instance A, also using instance A’s sa login as a catch-all.

For this setup I leave WinSrv2k22\WinSQL2022 unchanged from the previous demo, but I create a linked server on WinSrv2k22\WinSQL2019 that points to WinSrv2k22\WinSQL2022 and uses sa as a catch-all.

To test this setup’s behavior I need to modify the previous test query so that it daisy chains another execution from WinSrv2k22\WinSQL2019 to WinSrv2k22\WinSQL2022 via the LinkToSQL2022 linked server connection.


Here, the first result set is from the local instance (the one I’m directly connected to as SQLBothLogin via SSMS).
The second result set is the one obtained through LinkToSQL2019 from WinSrv2k22\WinSQL2019.
And the third one is obtained through LinkToSQL2022 from WinSrv2k22\WinSQL2022 by executing the relevant portion of T-SQL on WinSrv2k22\WinSQL2019 through LinkToSQL2019.

The impact in all 3 of these scenarios isn’t limited to just SQL Server’s level, with access to the sa account a user can leverage xp_cmdshell to interact with the instance’s host OS.
At which point, the instance’s service account, if not properly secured, may allow an attacker privileged access to the underlying OS.

Conclusion

SQL Server’s linked servers is a pretty useful feature when you need to move or sync data between instances, implement some in-house database sharding, or centralizing diagnostics/monitoring data from across your SQL Server environment into a single instance where you can have reports ran against said data.

The security risk comes when they’re incorrectly configured to give low privilege logins access to high privilege remote logins, but this can be avoided by correctly defining mappings and impersonations and staying away from “catch-all” types of configurations.

This is one of those features where you really want to be mindful of the principle of least privilege, and take the them to ensure you’re properly securing SQL Server linked servers.

You may also like

3 comments

Nathan O July 11, 2023 - 10:24

This is perfect timing because I have just inherited an environment filled with interconnected SQL Servers.

Reply
Rick September 3, 2025 - 21:10

Great article. This is one of the clearest explanations of linked server security settings I’ve ever seen.

Reply
Vlad Drumea September 8, 2025 - 21:20

Hi Rick,
Thank you for the feedback. I’m glad you found it useful.

Reply

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

This site uses Akismet to reduce spam. Learn how your comment data is processed.