АйТи Фреш
Главная / Статьи / 1С и базы данных
1С и базы данных

Как починить linked server после перехода на SQL Server 2025

Автор: Семёнов Евгений Сергеевич, директор ООО «АйТи-Фреш» · · ~18 мин чтения
Как починить linked server после перехода на SQL Server 2025
Иллюстрация к статье «Как починить 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 я тоже не советую.

Ошибки 7399 и 7303 — оболочка. Ищите рядом сообщение `SSL Provider: The certificate chain was issued by an authority that is not trusted` (в журнале оно приходит с кодом -2146893019): именно оно указывает на настоящую причину после обновления — самоподписанный или недоверенный сертификат на удалённом сервере.
Порядок действий: Почему объект сохранился, а соединение перестало работать — схема
Порядок действий: Почему объект сохранился, а соединение перестало работать. Открыть схему в полном размере

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=Mandatory;TrustServerCertificate=No`. `Optional`, флаг 17600 и отключение проверки сертификата допустимы только как ограниченный по времени аварийный мост.
Как починить linked server после перехода на SQL Server 2025 — схема
Схема к статье. Открыть схему в полном размере

Практика: что произошло в питомнике «Чистая порода»

Питомник собак «Чистая порода» — условный клиент с 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, а корректный выбор протокола для смешанных версий. Для маленькой организации это важно ещё и потому, что второй сервер никто не собирался обновлять ради одного отчёта.

Название организации и сетевые имена в примере условные. Архитектура, последовательность отказа и технические параметры приведены как обезличенный практический стенд.

Как подготовить сертификат, который примет 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.1
certreq -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. Сама настройка и выбор сертификата применяются только после перезапуска службы, поэтому окно работ планирую заранее.

Импорт корневого сертификата в профиль администратора не помогает `OPENQUERY`: соединение открывает служба SQL Server на исходном сервере, поэтому доверие настраивается в хранилище Local Computer этого узла.
Порядок действий: Как подготовить сертификат, который примет OLE DB 19 — схема
Порядок действий: Как подготовить сертификат, который примет OLE DB 19. Открыть схему в полном размере

Как безопасно пересоздать 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 и чтение необходимых объектов.

Не удаляйте linked server, пока не подтверждены удалённые реквизиты. SQL Server показывает имя сопоставленного логина, но не восстанавливает его пароль.

Проверка результата и допустимый аварийный откат

Кнопки 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, а понятная схема доверия и контролируемое продление.

Не оставляйте `-T17600`, `Encrypt=Optional` или отключённую проверку сертификата «до следующего обновления». На практике такая временная мера живёт годами и обнаруживается только во время следующей аварии.
Цифры и версии: Проверка результата и допустимый аварийный откат — схема
Цифры и версии: Проверка результата и допустимый аварийный откат. Открыть схему в полном размере

Частые вопросы

Можно ли просто добавить 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` и доверенный сертификат.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 💬 MAX: +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи