Как починить linked server после перехода на SQL Server 2025
После обновления linked server виден в SSMS, логины и параметры остались на месте, но первый же `OPENQUERY` заканчивается ошибками 7399 и 7303. Я, Семёнов Евгений Сергеевич, разбираю, почему SQL Server 2025 меняет поведение старого определения, какой режим шифрования выбираю для рабочих систем и как выпустить, привязать и проверить нормальный сертификат без небезопасного `TrustServerCertificate=Yes`.
Почему объект сохранился, а соединение перестало работать
Сам linked server — это всего лишь сохранённые метаданные: имя провайдера, адрес источника, каталог, параметры и сопоставления логинов. Обновление SQL Server не обязано удалять эту запись. Проверка начинается позже, когда OPENQUERY, четырёхчастное имя или sp_testlinkedserver заставляет движок загрузить провайдер и открыть реальное соединение. Поэтому ситуация «объект на месте, но запросы не работают» для меня не выглядит противоречием.
В SQL Server 2025, то есть ветке 17.x, имя провайдера MSOLEDBSQL для linked server по умолчанию означает OLE DB Driver 19. У него изменилось значение шифрования по умолчанию: вместо поведения версии 18 соединение фактически приходит к Encrypt=Mandatory. Если в старом определении отсутствует @provstr, а удалённый SQL Server предъявляет автоматически созданный самоподписанный сертификат либо цепочку от неизвестного удостоверяющего центра, драйвер разрывает соединение. Типичный результат — сообщение о недоверенной цепочке, затем ошибки 7399 и 7303.
Первым делом я фиксирую версию движка и текущее определение. Не начинаю с переустановки SSMS, проверки прав на таблицу или включения DTC: до них дело ещё не дошло.
SELECT @@VERSION AS sql_version;
SELECT name,
provider,
data_source,
provider_string,
catalog,
is_data_access_enabled,
is_rpc_out_enabled
FROM sys.servers
WHERE is_linked = 1;
EXEC master.dbo.sp_testlinkedserver N'VET_LINK';
SELECT name, file_version, product_version
FROM sys.dm_os_loaded_modules
WHERE name LIKE N'%msoledbsql%';Последний запрос требует серверного разрешения на просмотр состояния и может вернуть модуль только после попытки загрузки провайдера. На середину сентября 2026 года последний накопительный пакет — SQL Server 2025 CU8 (сборка 17.0.4075.5, 13 августа 2026 года), поверх него уже вышло исправление безопасности CU8 + GDR (17.0.4085.5, KB5122769, 8 сентября 2026 года); отдельно распространяемый OLE DB Driver — версия 19.4.2 от 22 мая 2026 года. Это не значит, что любая проблема лечится обновлением до этих номеров, но диагностировать древний драйвер вместо настройки TLS я тоже не советую.
- Сначала сохранить скрипт linked server, его параметры и сопоставления логинов.
- Затем проверить DNS, TCP-порт и точный текст внутренней ошибки провайдера.
- После этого решить вопрос с именем сервера, сертификатом и `Encrypt`.
- Права на удалённые объекты разбирать только после успешной инициализации источника данных.
Mandatory, Strict и TrustServerCertificate — не одно и то же
Для обычного производственного linked server я выбираю Encrypt=Mandatory, доверенный сертификат от корпоративного УЦ, TrustServerCertificate=No и подключение по FQDN. Это даёт шифрование канала и проверку личности удалённого SQL Server, но не привязывает всю инфраструктуру к TDS 8.0. Такой вариант работает и с поддерживаемыми старыми целевыми версиями SQL Server. В смешанном контуре это разумнее, чем включать Strict только потому, что слово звучит надёжнее.
Encrypt=Strict — отдельный режим, а не усиленный синоним Mandatory. Он включает TDS 8.0, шифрующий соединение с самого начала обмена, требует OLE DB Driver не ниже 19.2 и целевой SQL Server 2022 или новее. Сертификат проверяется всегда, а TrustServerCertificate обойти эту проверку не может. Я использую Strict, когда обе стороны находятся под нашим управлением, их совместимость проверена и в требованиях действительно указан TDS 8.0. Для SQL Server 2019 на удалённой стороне этот режим не подходит.
TrustServerCertificate=Yes не делает сертификат доверенным. Канал шифруется, но драйвер перестаёт удостоверять, с каким сервером разговаривает, поэтому остаётся возможность подмены узла. В OLE DB Driver 19 параметр строки подключения учитывается вместе с клиентской настройкой реестра HKLM\SOFTWARE\Microsoft\MSSQLServer\Client\SNI19.0\GeneralFlags\Flag2: драйвер выбирает более безопасный из двух вариантов, и проверка отключается только если её отключение разрешают оба уровня. По таблице Microsoft значение по умолчанию равно 1, то есть разрешает, но в версиях 19.0–19.3 установщик переносил значение из настроек 18-й версии — если там стоял 0, TrustServerCertificate=Yes в @provstr просто игнорируется. Отсюда знакомая картина: администратор дописал параметр, а поведение не изменилось. Я реестр ради такого обхода не ослабляю.
- `Encrypt=Optional`: клиент не требует TLS и не проверяет сертификат; если на сервере не включён Force Encryption, шифруются только пакеты входа, а данные идут открытым текстом.
- `Encrypt=Mandatory`: TLS обязателен; при `TrustServerCertificate=No` проверяются цепочка доверия, срок и имя сервера.
- `Encrypt=Strict`: обязателен TDS 8.0 и полноценная проверка сертификата; обход через `TrustServerCertificate` не поддерживается.
- `HostNameInCertificate`: задаёт имя, с которым сравниваются CN или SAN, но не исправляет просроченный, отозванный или недоверенный сертификат.
Практика: что произошло в питомнике «Чистая порода»
Питомник собак «Чистая порода» — условный клиент с 15 рабочими местами: администраторы, кинологи, ветеринарный врач и бухгалтерия. Сервер учётной системы CP-SQL-APP (продажи щенков, договоры, склад кормов) работал на Windows Server 2022, 4 vCPU и 16 Гбайт RAM; его обновили с SQL Server 2019 до SQL Server 2025 Standard CU8, сборка 17.0.4075.5, вместе с которым был установлен OLE DB Driver 19. Ветеринарная и племенная база — прививки, обработки, родословные и помёты — осталась на CP-SQL-VET: Windows Server 2019, 2 vCPU, 8 Гбайт RAM, SQL Server 2019 CU32 с июльским GDR, сборка 15.0.4480.2, статический TCP-порт 1433.
Linked server VET_LINK обслуживал четыре отчёта (график прививок, карточка щенка перед продажей, сводка по помётам, остатки препаратов) и два задания SQL Server Agent. Старое определение содержало MSOLEDBSQL, источник CP-SQL-VET и пустую provider string. Через несколько минут после запуска обновлённого экземпляра первое задание упало: провайдер сообщил SSL Provider: The certificate chain was issued by an authority that is not trusted, затем появились 7399 и 7303. TCP 1433 открывался, SQL-аутентификация была исправна, а из старого SSMS с ноутбука администратора соединение проходило. Последнее только мешало диагностике: ноутбук, процесс sqlservr.exe и OLE DB 19 используют разные драйверы, контексты и хранилища сертификатов.
На ветеринарном сервере SQL Server использовал автоматически сформированный самоподписанный сертификат. Одновременно linked server обращался по короткому имени. Мы могли вернуть старое поведение через Encrypt=Optional, но я выбрал нормальную схему: сертификат от внутреннего AD CS, SAN с коротким именем и FQDN, доверие к корневому УЦ на сервере-источнике и явный Encrypt=Mandatory. Strict здесь исключили сразу: TDS 8.0 поддерживается начиная с SQL Server 2022, а целевой сервер версии 2019. Это не компромисс с безопасностью TLS, а корректный выбор протокола для смешанных версий. Для маленькой организации это важно ещё и потому, что второй сервер никто не собирался обновлять ради одного отчёта.
- Источник: SQL Server 2025 Standard CU8, OLE DB Driver 19.
- Цель: SQL Server 2019 CU32 + GDR (15.0.4480.2), TCP 1433, самоподписанный сертификат.
- До обновления: provider string пустая, соединение зависело от значений по умолчанию OLE DB 18 (`Encrypt=No`).
- После исправления: FQDN, сертификат внутреннего УЦ, `Encrypt=Mandatory`, проверка сертификата включена.
Как подготовить сертификат, который примет OLE DB 19
Сертификат устанавливается на целевой SQL Server — в нашем случае CP-SQL-VET. Нужны закрытый ключ, назначение Server Authentication с OID 1.3.6.1.5.5.7.3.1, действующий срок и RSA-ключ, созданный совместимым legacy CSP с KeySpec=AT_KEYEXCHANGE. В SAN я включаю все имена, реально используемые клиентами: cp-sql-vet.pitomnik.local и cp-sql-vet. Надеяться только на CN уже не стоит. Закрытый ключ должен быть доступен учётной записи службы SQL Server, но экспортировать его без необходимости не нужно.
В домене с AD CS запрос можно сформировать через certreq. Конкретный INF нашего стенда выглядел так:
[Version]
Signature="$Windows NT$"
[NewRequest]
Subject="CN=cp-sql-vet.pitomnik.local"
MachineKeySet=TRUE
Exportable=FALSE
KeyLength=2048
KeySpec=1
KeyAlgorithm=RSA
ProviderName="Microsoft RSA SChannel Cryptographic Provider"
ProviderType=12
RequestType=PKCS10
HashAlgorithm=sha256
[RequestAttributes]
CertificateTemplate=WebServer
[Extensions]
2.5.29.17="{text}"
_continue_="dns=cp-sql-vet.pitomnik.local&"
_continue_="dns=cp-sql-vet"
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.1certreq -new C:\TLS\sql-vet.inf C:\TLS\sql-vet.req
certreq -submit -config "CP-CA01\PITOMNIK-CA" C:\TLS\sql-vet.req C:\TLS\sql-vet.cer
certreq -accept C:\TLS\sql-vet.cerИмя УЦ в команде относится к условному стенду. В рабочей сети его берут из вашей PKI. Без строки CertificateTemplate корпоративный УЦ запрос не примет; вместо стандартного WebServer часто используют копию шаблона, в которой администратор УЦ разрешил выпуск на legacy CSP и дал серверу право Enroll. Проверить результат стоит сразу: у подходящего сертификата certutil -v -store My <отпечаток> показывает KeySpec = 1 -- AT_KEYEXCHANGE и Server Authentication в Enhanced Key Usage. Сертификат с ключом от Key Storage Provider (KeySpec = 0) SQL Server не использует.
После выпуска я проверяю сертификат в Cert:\LocalMachine\My, выдаю служебной учётной записи SQL Server право чтения закрытого ключа и выбираю сертификат в SQL Server Configuration Manager: SQL Server Network Configuration → Protocols for instance → Certificate. Затем перезапускаю именно целевой экземпляр SQL Server. Force Encryption ради одного linked server включать необязательно: шифрование уже требует клиентский Encrypt=Mandatory. На CP-SQL-APP, который является TLS-клиентом, цепочка внутреннего УЦ должна находиться в хранилищах Local Computer, а не только Current User.
Get-ChildItem Cert:\LocalMachine\My |
Where-Object Subject -eq 'CN=cp-sql-vet.pitomnik.local' |
Format-List Subject,DnsNameList,NotAfter,Thumbprint,HasPrivateKey
Resolve-DnsName cp-sql-vet.pitomnik.local
Test-NetConnection cp-sql-vet.pitomnik.local -Port 1433
Get-ChildItem Cert:\LocalMachine\Root |
Where-Object Subject -eq 'CN=PITOMNIK Root CA' |
Format-List Subject,Thumbprint,NotAfterОтдельно про Force Encryption. В том же окне SQL Server Configuration Manager на вкладке Flags параметр Force Encryption = Yes заставляет сервер шифровать все входящие соединения, включая старые приложения с Encrypt=Optional. Я включаю его на целевом сервере, когда нужна единая политика для всех клиентов, но только после того, как привязан доверенный сертификат: при самоподписанном сертификате флаг не решает проблему OLE DB 19, а лишь заставляет более старых клиентов без проверки шифровать трафик, не удостоверяя сервер. Перед включением я прохожу по списку приложений, которые подключаются к базе, — на маленьком контуре это обычно учётная программа, отчёты и пара рабочих станций с ODBC — и проверяю, что их драйверы умеют TLS 1.2. Сама настройка и выбор сертификата применяются только после перезапуска службы, поэтому окно работ планирую заранее.
- Серверный сертификат с закрытым ключом — `Local Computer\Personal` на целевом SQL Server.
- Корневой сертификат УЦ — `Local Computer\Trusted Root Certification Authorities` на исходном сервере.
- Промежуточный УЦ, если он есть, — `Local Computer\Intermediate Certification Authorities`.
- У службы SQL Server на целевом узле должно быть право чтения закрытого ключа.
Как безопасно пересоздать linked server
Provider string нельзя поменять через обычный sp_serveroption. Перед удалением я сохраняю определение, результат sp_helplinkedsrvlogin и все серверные опции. Пароли существующих удалённых логинов SQL Server обратно из системных представлений получить нельзя. Если пароль неизвестен, сначала ротируйте его и положите в корпоративное хранилище секретов, иначе после удаления вы получите вторую аварию, уже не связанную с TLS.
Рабочее определение для стенда получилось таким. FQDN совпадает с SAN сертификата; HostNameInCertificate указан явно, чтобы будущая замена DNS-алиаса не сделала проверку неочевидной.
USE master;
GO
EXEC master.dbo.sp_dropserver
@server = N'VET_LINK',
@droplogins = N'droplogins';
GO
EXEC master.dbo.sp_addlinkedserver
@server = N'VET_LINK',
@srvproduct = N'',
@provider = N'MSOLEDBSQL',
@datasrc = N'cp-sql-vet.pitomnik.local',
@provstr = N'Encrypt=Mandatory;TrustServerCertificate=No;HostNameInCertificate=cp-sql-vet.pitomnik.local';
GO
EXEC master.dbo.sp_serveroption
@server = N'VET_LINK',
@optname = N'data access',
@optvalue = N'true';
GOПараметр TrustServerCertificate=No можно было опустить, но я оставляю его как зафиксированное намерение. Секрет сопоставления linked_app_ro мы подали отдельным закрытым скриптом через систему развёртывания и sp_addlinkedsrvlogin; публиковать пароль или встраивать его в общий миграционный файл не следует.
RPC Out я включаю только тогда, когда приложение действительно выполняет удалённые процедуры. Для одного OPENQUERY он не нужен. Аналогично не копирую вслепую collation compatible=true: ошибочная настройка сортировки способна дать неверные результаты удалённой фильтрации. После пересоздания проверяю, что у обычного прикладного логина нет универсального self-mapping и что удалённая учётная запись получила только CONNECT и чтение необходимых объектов.
- Снимите конфигурацию и login mappings до `sp_dropserver`.
- Заранее подготовьте пароль удалённого технического логина или Kerberos-делегирование.
- Используйте FQDN, присутствующий в SAN сертификата.
- Возвращайте только те server options, которые действительно нужны приложению.
- Тестируйте запрос под тем же локальным логином, от которого работает задание или приложение.
Проверка результата и допустимый аварийный откат
Кнопки Test Connection недостаточно. Я проверяю инициализацию, реальный бизнес-запрос и факт шифрования удалённой сессии. Для просмотра sys.dm_exec_connections тестовой удалённой учётной записи временно потребуется VIEW SERVER STATE на SQL Server 2019; после проверки разрешение надо убрать.
EXEC master.dbo.sp_testlinkedserver N'VET_LINK';
SELECT TOP (10) DogId, VaccinationDate, VaccineCode
FROM OPENQUERY(VET_LINK, '
SELECT DogId, VaccinationDate, VaccineCode
FROM VetDb.dbo.Vaccinations
ORDER BY VaccinationDate DESC');
SELECT net_transport, protocol_type, encrypt_option
FROM OPENQUERY(VET_LINK, '
SELECT net_transport, protocol_type, encrypt_option
FROM sys.dm_exec_connections
WHERE session_id = @@SPID');Для выбранной схемы ожидаю encrypt_option = TRUE. Значение protocol_type не доказывает режим Strict: TDS 8.0 здесь и не должен использоваться, поскольку цель работает на SQL Server 2019.
Если работа уже стоит, Microsoft предлагает два аварийных пути: пересоздать подключение с Encrypt=Optional либо — если определение изменить нельзя — включить trace flag 17600, сохраняющий для linked servers поведение и значения по умолчанию OLE DB 18. Я предпочту стартовый параметр -T17600, если быстро пересоздать десятки объектов нельзя: он централизован, заметен в конфигурации запуска и позволяет выиграть окно на выпуск сертификатов. Но это технический долг с датой удаления, а не исправление. Encrypt=Mandatory;TrustServerCertificate=Yes тоже годится лишь для короткой диагностики в изолированной сети; ради него я не меняю Flag2 в реестре.
В «Чистой породе» от обнаружения причины до восстановления обоих заданий прошло 74 минуты, включая выпуск и привязку сертификата. Затем мы выполнили 20 ручных запросов по всем четырём отчётам, дождались двух полных циклов SQL Agent и оставили мониторинг на 72 часа. За это время прошло около 600 обращений без ошибок 7303/7399; ночная сводка по прививкам заняла 1 минуту 54 секунды против прежних 1 минуты 52 секунд — разницу считаю шумом. В мониторинг добавили срок сертификата с предупреждениями за 45 и 15 дней. Вот это для меня законченная работа: не просто снова зелёный OPENQUERY, а понятная схема доверия и контролируемое продление.
- `sp_testlinkedserver` успешно инициализирует провайдер.
- Бизнес-запрос возвращает ожидаемые строки под рабочим логином.
- Удалённая DMV показывает `encrypt_option = TRUE`.
- Задания SQL Server Agent проходят несколько полных циклов.
- Срок сертификата и ошибки linked server попадают в мониторинг.
Частые вопросы
Можно ли просто добавить TrustServerCertificate=Yes?
Технически это восстанавливает зашифрованное соединение в режиме Mandatory, если клиентская настройка реестра OLE DB 19 (`SNI19.0\GeneralFlags\Flag2`) тоже разрешает доверять сертификату. Но сервер при этом не проходит проверку личности, и Microsoft прямо не рекомендует такой вариант для production. Я использую сертификат доверенного УЦ и `TrustServerCertificate=No`.
Чем Mandatory отличается от Strict?
Mandatory требует TLS, но работает через TDS 7.x и совместим с более старыми целевыми SQL Server. Strict принудительно использует TDS 8.0, требует SQL Server 2022 или новее и OLE DB Driver 19.2+, всегда проверяет сертификат и не поддерживает обход через TrustServerCertificate.
Почему сертификат доверен в SSMS, но не в OPENQUERY?
SSMS может работать на другом компьютере, под другим пользователем и через другой драйвер. Linked server открывает процесс SQL Server на исходном узле, поэтому цепочка УЦ должна быть доверена в хранилище Local Computer именно этого сервера.
Нужно ли включать Force Encryption на целевом SQL Server?
Для конкретного linked server необязательно: `Encrypt=Mandatory` уже требует TLS со стороны клиента. Force Encryption (SQL Server Configuration Manager → Protocols → Flags) имеет смысл как серверная политика для всех подключений, но включать его стоит только вместе с доверенным сертификатом и после проверки всех приложений и драйверов; изменение вступает в силу после перезапуска службы.
Можно ли оставить trace flag 17600 навсегда?
Флаг возвращает linked servers к поведению OLE DB Driver 18 и полезен для аварийного восстановления, когда объекты нельзя быстро пересоздать. Постоянным решением я его не считаю: настройте сертификаты и явный `Encrypt`, проверьте соединения и удалите флаг в согласованное окно.
Чем опасен Encrypt=Optional в @provstr?
С `Encrypt=Optional` драйвер не требует TLS и не проверяет сертификат: если на удалённом сервере не включён Force Encryption, шифруются только пакеты входа, а запросы и результаты — например, данные владельцев и договоры — идут по сети открытым текстом. Это быстрый способ вернуть работу после обновления, но его нужно фиксировать как временный обход с датой замены на `Encrypt=Mandatory` и доверенный сертификат.
Источники
- Microsoft Learn — Breaking changes to Database Engine features in SQL Server 2025 — Раздел «Linked server connections fail after an upgrade» и текст ошибки `SSL Provider: The certificate chain was issued by an authority that is not trusted`: https://learn.microsoft.com/en-us/sql/database-engine/breaking-changes-to-database-engine-features-in-sql-server-2025
- Microsoft Learn — What's new in SQL Server 2025 — TDS 8.0 и TLS 1.3 для linked servers, репликации и log shipping; ссылка на breaking changes: https://learn.microsoft.com/en-us/sql/sql-server/what-s-new-in-sql-server-2025
- Microsoft Learn — Linked Servers (Database Engine) — Раздел «SQL Server 2025 and MSOLEDBSQL version 19», актуален для SQL Server 2025 (17.x): https://learn.microsoft.com/en-us/sql/relational-databases/linked-servers/linked-servers-database-engine?view=sql-server-ver17
- Microsoft Learn — sys.sp_addlinkedserver — Синтаксис `@provstr`, примеры `Encrypt=Optional`, `Mandatory` и `Strict`, версия SQL Server 2025: https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-addlinkedserver-transact-sql?view=sql-server-ver17
- Microsoft Learn — Encryption and certificate validation — Матрица режимов шифрования и проверки сертификата OLE DB Driver 19: https://learn.microsoft.com/en-us/sql/connect/oledb/features/encryption-and-certificate-validation?view=sql-server-ver17
- Microsoft Learn — Certificate requirements for SQL Server — Требования к SAN, EKU Server Authentication, KeySpec AT_KEYEXCHANGE (legacy CSP), закрытому ключу и проверка через certutil: https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/certificate-requirements?view=sql-server-ver17
- Microsoft Learn — TDS 8.0 — `Encrypt=Strict` поддерживается с SQL Server 2022, требует OLE DB Driver 19.2.0+, `TrustServerCertificate` не допускается: https://learn.microsoft.com/en-us/sql/relational-databases/security/networking/tds-8?view=sql-server-ver17
- Microsoft Learn — Using connection string keywords with OLE DB Driver — Описание `Encrypt`, `TrustServerCertificate` и `HostNameInCertificate` для MSOLEDBSQL 19: https://learn.microsoft.com/en-us/sql/connect/oledb/applications/using-connection-string-keywords-with-oledb-driver-for-sql-server?view=sql-server-ver17
- Microsoft Learn — Registry settings — Ключ `HKLM\SOFTWARE\Microsoft\MSSQLServer\Client\SNI19.0`, `GeneralFlags\Flag1` (Force Protocol Encryption) и `Flag2` (Trust Server Certificate): https://learn.microsoft.com/en-us/sql/connect/oledb/features/registry-settings?view=sql-server-ver17
- Microsoft Learn — Release notes for OLE DB Driver — OLE DB Driver 19.4.2, выпущен 22 мая 2026 года: https://learn.microsoft.com/en-us/sql/connect/oledb/release-notes-for-oledb-driver-for-sql-server?view=sql-server-ver17
- Microsoft Learn — SQL Server 2025 build versions — KB5005684: CU8 — сборка 17.0.4075.5 от 13 августа 2026 года, CU8 + GDR — 17.0.4085.5 (KB5122769) от 8 сентября 2026 года: https://learn.microsoft.com/en-us/troubleshoot/sql/releases/sqlserver-2025/build-versions
- Microsoft Learn — SQL Server 2019 build versions — KB4518398: CU32 (15.0.4430.1) и сборки CU32 + GDR, включая 15.0.4480.2 (KB5102335) от 14 июля 2026 года: https://learn.microsoft.com/en-us/troubleshoot/sql/releases/sqlserver-2019/build-versions
