Issues with DAC connection
Verified issue does not already exist?
I have searched and found no existing issue
What error did you receive?
Could not connect because the maximum number of '1' dedicated administrator connections already exists. Before a new connection can be made, the existing dedicated administrator connection must be dropped, either by logging off or ending the process
Steps to Reproduce
Issue 1: Running Export-DbaLinkedServer -SqlInstance SRV will result in error mentioned above in server logs. As described in https://github.com/dataplat/dbatools/pull/9921 we should open DAC connection before calling Get-DecryptedObject, so Export-DbaLinkedServer should open DAC connection too? Issue 2: After https://github.com/dataplat/dbatools/pull/9921 merged, Copy-DbaLinkedServer will always try to open DAC connection despite of "-ExcludePasswords" parameter. Should we check this parameter before opening connection? Issue 3: Root issue of error above is that System.Data.SqlClient.SQLConnection tries to connect to all IP's simultaneously. So when we try to open DAC connection in Get-DecryptedObject it opens in "Invoke-Command2" function and executes on source server locally. Locally we have multiple IP's per server by default (local, ipv6, ipv4 etc) and DAC connection tries to open multiple times to each ip simultaneously
Please confirm that you are running the most recent version of dbatools
Major Minor Build Revision
2 7 13 -1
Other details or mentions
I don't found how i can limit this behavior of System.Data.SqlClient.SQLConnection, so maybe DAC connection should perform directly to IP instead of DNS name if it connects to local machine?
What PowerShell host was used when producing this error
Windows PowerShell (powershell.exe)
PowerShell Host Version
Name Value
PSVersion 5.1.20348.4294 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.20348.4294 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1
SQL Server Edition and Build number
Microsoft SQL Server 2016 (SP3-GDR) (KB5058718) - 13.0.6460.7 (X64) May 29 2025 21:37:21 Copyright (c) Microsoft Corporation Enterprise Edition: Core-based Licensing (64-bit) on Windows Server 2022 Datacenter 10.0 <X64> (Build 20348: )
.NET Framework Version
PSChildName Version
Client 4.8.04161 Full 4.8.04161 Client 4.0.0.0
thank you for the report, @Phaere. @claude can you please do some deep research and ultrathink about the best solution? this is a challenging, recurring problem.
Claude finished @potatoqualitee's task in 5m 8s —— View job
Deep Analysis: DAC Connection Issues ✅
I've completed comprehensive research on the DAC connection problem. Here are my findings and recommended solutions.
Problem Summary
Issue 1 - Export-DbaLinkedServer missing DAC connection:
- Location:
Export-DbaLinkedServer.ps1:149 - Calls
Get-DecryptedObjectwithout first establishing a DAC connection - Unlike
Copy-DbaLinkedServerwhich opens DAC in thebeginblock (line 286) - Forces
Get-DecryptedObjectto attempt DAC connection internally viaInvoke-Command2
Issue 2 - Copy-DbaLinkedServer unnecessary DAC:
- Location:
Copy-DbaLinkedServer.ps1:286 - Opens DAC connection unconditionally in
beginblock - But
Get-DecryptedObjectis only called when-ExcludePasswordis NOT set (line 136) - Wastes the precious single DAC connection when passwords aren't being copied
Issue 3 - Root cause (SQL Client parallel connection attempts):
- When
Get-DecryptedObjectcreates DAC connection string insideInvoke-Command2:- Non-clustered (line 110):
"Server=ADMIN:$fullComputerName\$instance;Trusted_Connection=True;Pooling=false" - Clustered (line 127):
"Server=ADMIN:$sourceName;Trusted_Connection=True;Pooling=false;"
- Non-clustered (line 110):
System.Data.SqlClient.SQLConnectionresolves hostname to multiple IPs (IPv4, IPv6, localhost, etc.)- SQL Client attempts connections to all IPs simultaneously
- DAC only allows 1 connection maximum, so parallel attempts trigger: "maximum number of '1' dedicated administrator connections already exists"
Root Cause Analysis
The connection flow:
Export-DbaLinkedServer/Copy-DbaLinkedServer
→ Get-DecryptedObject (private function)
→ Invoke-Command2 (executes on target machine)
→ New System.Data.SqlClient.SQLConnection(connString)
→ Resolves hostname → [192.168.1.100, ::1, 127.0.0.1, fe80::...]
→ Attempts parallel connections to ALL IPs
→ ERROR: Only 1 DAC connection allowed!
On modern Windows servers with multiple network interfaces, a hostname typically resolves to:
- IPv4 loopback:
127.0.0.1 - IPv6 loopback:
::1 - Physical network IPv4:
192.168.x.xor10.x.x.x - Physical network IPv6:
fe80::...
SQL Client's default behavior is to attempt connections to all resolved addresses simultaneously for faster connection establishment. This is fine for normal connections but fatal for DAC since only ONE DAC connection is allowed per SQL Server instance.
Recommended Solutions
I recommend a multi-part fix addressing all three issues:
Solution for Issue 3 (Root Cause - MOST CRITICAL)
Modify Get-DecryptedObject.ps1 to use 127.0.0.1 for local DAC connections:
For non-clustered instances (line 110), change:
# CURRENT (problematic)
$connString = "Server=ADMIN:$fullComputerName\$instance;Trusted_Connection=True;Pooling=false"
# PROPOSED (use 127.0.0.1 to avoid multi-IP resolution)
$connString = "Server=ADMIN:127.0.0.1\$instance;Trusted_Connection=True;Pooling=false"
Rationale:
127.0.0.1is a single IP address, preventing parallel connection attempts- DAC connections are always local (executed via
Invoke-Command2on the target machine) - Using loopback IP is standard practice for local SQL connections
- Avoids DNS resolution overhead
For clustered instances, the connection already uses the server name which is required for remote DAC.
Solution for Issue 1 (Export-DbaLinkedServer)
Add DAC connection establishment in Export-DbaLinkedServer.ps1:
Since Export-DbaLinkedServer processes multiple instances via pipeline, the DAC connection should be established in the process block for each instance when passwords are being exported (when -ExcludePassword is NOT specified).
The pattern should follow Copy-DbaLinkedServer but adapted for the pipeline pattern used in Export-DbaLinkedServer.
Solution for Issue 2 (Copy-DbaLinkedServer)
Conditionally open DAC in Copy-DbaLinkedServer.ps1:
Modify the begin block (currently line 286) to only establish DAC when passwords will be retrieved:
begin {
if (-not $script:isWindows) {
Stop-Function -Message "Copy-DbaCredential is only supported on Windows"
return
}
$null = Test-ElevationRequirement -ComputerName $Source.ComputerName
if ($Force) { $ConfirmPreference = 'none' }
# Only establish DAC if we're actually retrieving passwords
if (-not $ExcludePassword) {
try {
Write-Message -Level Verbose -Message "Opening dedicated admin connection for password retrieval."
$sourceServer = Connect-DbaInstance -SqlInstance $Source -SqlCredential $SourceSqlCredential -DedicatedAdminConnection -WarningAction SilentlyContinue
} catch {
Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $Source
return
}
# ... rest of validation ...
} else {
# When ExcludePassword is used, don't waste the DAC connection
try {
$sourceServer = Connect-DbaInstance -SqlInstance $Source -SqlCredential $SourceSqlCredential
} catch {
Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $Source
return
}
}
# ... rest of begin block ...
}
Alternative Approaches Considered
Alternative 1: Add connection string parameters
- Add
MultiSubnetFailover=Falseto prevent parallel attempts - Rejected: Still attempts multiple IPs sequentially, slower and may still fail
Alternative 2: Resolve to IP before connecting
- Query DNS to get single IP, use that in connection string
- Rejected: Adds complexity, DNS resolution may still return multiple IPs
Alternative 3: Use (local) or . notation
- Change connection string to use
ADMIN:(local)\$instance - Rejected: Still resolves to multiple loopback addresses on some systems
Alternative 4: Refactor to pass DAC connection to Get-DecryptedObject
- Pass an already-opened DAC server object instead of opening inside
- Considered but complex: Would require significant refactoring of
Get-DecryptedObjectsignature
Implementation Priority
- CRITICAL: Fix Issue 3 (
Get-DecryptedObjectusing127.0.0.1) - This solves the root cause - HIGH: Fix Issue 2 (
Copy-DbaLinkedServerconditional DAC) - Prevents unnecessary DAC usage - MEDIUM: Fix Issue 1 (
Export-DbaLinkedServerDAC pattern) - Improves reliability
Additional Considerations
Testing Requirements:
- Test on servers with multiple network interfaces
- Test on both non-clustered and clustered instances
- Test
Export-DbaLinkedServerwith and without-ExcludePassword - Test
Copy-DbaLinkedServerwith and without-ExcludePassword - Verify DAC connection is properly released after use
Backward Compatibility:
- Using
127.0.0.1is compatible with all SQL Server versions - Changes to conditionally open DAC are internal logic improvements
- No breaking changes to public API
Documentation:
- Update function comments to clarify DAC usage
- Note that password decryption requires DAC connection
- Explain that only one DAC connection is allowed per instance
Questions for Maintainers
- Should we also update other commands that might use DAC? (e.g.,
Invoke-DbaDbDecryptObject,Copy-DbaCredential) - Should we add a common private function for DAC connection string generation to centralize this logic?
- Do you want me to implement these fixes? I can create a PR with all three solutions if you approve this approach.
The user reported this as a "challenging, recurring problem" and you've correctly identified the root cause. The 127.0.0.1 fix is elegant, simple, and should resolve the core issue immediately.