IISからSQL Server Expressに接続できない時の解決策|アプリケーションプールIDへの権限付与をsqlcmdで完全解説

ASP.NET Core を IIS で動かすと SQL Server Express だけ「IIS だと失敗・コマンドだと成功」という落差に悩まされがちです。原因はネットワークではなく“実行アカウントの違い”。本稿では GUI(SSMS)なし、sqlcmdだけでアプリケーション プール ID に必要権限を付与し、安定接続できるまでを一気通貫で解説します。

目次

IIS から SQL Server Express に接続できない問題

質問の前提と典型的な現象

項目状況
OS / ミドルウェアWindows Server 2022 / IIS / SQL Server Express
アプリASP.NET Core 9.0
CLI 実行dotnet MyP.dll では接続成功
IIS 実行SQL 認証エラー(ログイン失敗、または DB へのマッピングなし)

なぜ CLI は成功し、IIS は失敗するのか(原因の整理)

同じコードでも、実行主体(Windows アカウント)が異なれば SQL Server が認可する主体も変わります。

実行コンテキストWindows アカウントSQL Server に見える主体
コマンドライン(手動)サインイン中の自分のアカウントDOMAIN\YourName 等
IIS(アプリケーション プール)アプリケーション プールの IDIIS APPPOOL\<AppPool名>(既定: ApplicationPoolIdentity)

初期状態では IIS APPPOOL\<AppPool名> は SQL Server に登録されておらず、データベース ユーザーでもないため、ログインできない/DB に入れないのが失敗の本質です。

結論(先にやることの全体像)

  • アプリプールの ID を SQL Server のサーバー ログインとして作成する。
  • 対象データベースにユーザーを作成してログインと関連付ける。
  • 最低限のロール(読み書き中心なら db_datareader と db_datawriter)または用途に合うカスタム ロールを付与する。
  • 接続文字列が Windows 認証(統合認証)であることを確認する。

sqlcmd だけで完結:権限付与の手順

前提の確認(全部コマンドでOK)

  1. アプリプール名の確認(GUIを使わず) C:\Windows\System32\inetsrv\appcmd list apppool /text:"name,processModel.identityType" ApplicationPoolIdentity で動かしている場合、Windows 主体名は IIS APPPOOL\<AppPool名> になります。
  2. SQL Server インスタンス名(Express 既定は .\SQLEXPRESS)
  3. 実行アカウントの権限:これから実行する sqlcmd の主体は SQL Server の sysadmin である必要があります(インストール時に指定した管理者等)。確認は以下。 sqlcmd -S .\SQLEXPRESS -E -Q "SELECT IS_SRVROLEMEMBER('sysadmin') AS is_sysadmin;"

ステップ 1:アプリプール ID をサーバー ログインとして登録

sqlcmd -S .\SQLEXPRESS -E -Q "CREATE LOGIN [IIS APPPOOL\&lt;YourAppPoolName&gt;] FROM WINDOWS;"

既に存在する場合はエラーになりますが無害です(後述の「よくあるエラーと対処」を参照)。

ステップ 2:データベース ユーザーを作成し、ログインと関連付け

sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "CREATE USER [IIS APPPOOL\&lt;YourAppPoolName&gt;] FOR LOGIN [IIS APPPOOL\&lt;YourAppPoolName&gt;];"

ステップ 3:最低限のロールを付与(読み書き中心)

sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "ALTER ROLE db_datareader ADD MEMBER [IIS APPPOOL\&lt;YourAppPoolName&gt;];"
sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "ALTER ROLE db_datawriter ADD MEMBER [IIS APPPOOL\&lt;YourAppPoolName&gt;];"

ストアド実行が必要な場合は必要最小限で付与します。

sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "GRANT EXECUTE TO [IIS APPPOOL\&lt;YourAppPoolName&gt;];"

ステップ 4:作成結果を確認

sqlcmd -S .\SQLEXPRESS -E -Q "SELECT name,type_desc FROM sys.server_principals WHERE name=N'IIS APPPOOL\&lt;YourAppPoolName&gt;';"
sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "SELECT name,type_desc FROM sys.database_principals WHERE name=N'IIS APPPOOL\&lt;YourAppPoolName&gt;';"

ワンショットで安全に実行(冪等化スクリプト)

初回でも再実行でも安全に流せる T‑SQL を sqlcmd 経由で投下します。

set APPPOOL=<YourAppPoolName>
set DB=<YourDatabase>

sqlcmd -S .\SQLEXPRESS -E -Q "IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE name = N'IIS APPPOOL%APPPOOL%') CREATE LOGIN [IIS APPPOOL%APPPOOL%] FROM WINDOWS;"
sqlcmd -S .\SQLEXPRESS -E -d %DB% -Q "IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = N'IIS APPPOOL%APPPOOL%') CREATE USER [IIS APPPOOL%APPPOOL%] FOR LOGIN [IIS APPPOOL%APPPOOL%];"
sqlcmd -S .\SQLEXPRESS -E -d %DB% -Q "IF NOT EXISTS (SELECT 1 FROM sys.database_role_members m JOIN sys.database_principals r ON m.role_principal_id=r.principal_id JOIN sys.database_principals u ON m.member_principal_id=u.principal_id WHERE r.name='db_datareader' AND u.name=N'IIS APPPOOL%APPPOOL%') ALTER ROLE db_datareader ADD MEMBER [IIS APPPOOL%APPPOOL%];"
sqlcmd -S .\SQLEXPRESS -E -d %DB% -Q "IF NOT EXISTS (SELECT 1 FROM sys.database_role_members m JOIN sys.database_principals r ON m.role_principal_id=r.principal_id JOIN sys.database_principals u ON m.member_principal_id=u.principal_id WHERE r.name='db_datawriter' AND u.name=N'IIS APPPOOL%APPPOOL%') ALTER ROLE db_datawriter ADD MEMBER [IIS APPPOOL%APPPOOL%];" 

より細かい最小権限(推奨パターン)

業務要件が明確なら、カスタム ロールにスコープを限定します。

sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name='app_rw') CREATE ROLE app_rw;"
sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO app_rw;"
sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "GRANT EXECUTE ON SCHEMA::dbo TO app_rw;"
sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "ALTER ROLE app_rw ADD MEMBER [IIS APPPOOL\&lt;YourAppPoolName&gt;];"

接続文字列の要点(ASP.NET Core)

Windows 認証(統合認証)を使う場合:

// appsettings.json
"ConnectionStrings": {
  "Default": "Server=.\\SQLEXPRESS;Database=&lt;YourDatabase&gt;;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=True;"
}
  • Trusted_Connection=True または Integrated Security=True を指定。
  • 近年のドライバは既定で Encrypt=True のため、自己署名や開発環境では TrustServerCertificate=True を併記しておくと初期トラブルを避けやすい(本番は適切な証明書を構成)。

SQL ログインを使う場合(今回は不要だが比較のため):

"Server=.\\SQLEXPRESS;Database=&lt;YourDatabase&gt;;User ID=&lt;SqlUser&gt;;Password=&lt;Secret&gt;;TrustServerCertificate=True;"

アプリプール ID の確認・切替をコマンドで行う

目的コマンド備考
ID を確認appcmd list apppool /text:"name,processModel.identityType"既定は ApplicationPoolIdentity
ApplicationPoolIdentity に設定appcmd set apppool /apppool.name:<AppPool> /processModel.identityType:ApplicationPoolIdentityこの記事の手順はこの前提で説明
NetworkService に変更appcmd set apppool /apppool.name:<AppPool> /processModel.identityType:NetworkService主体名は NT AUTHORITY\NETWORK SERVICE になる
特定ユーザーに変更appcmd set apppool /apppool.name:<AppPool> /processModel.identityType:SpecificUser /processModel.userName:<DOMAIN\User> /processModel.password:<Password>資格情報の保護とローテーションに注意

よくあるエラーと原因・対処

エラーメッセージ例原因対処
Login failed for user ‘IIS APPPOOL\…’(エラー 18456)サーバー ログインがない/無効ステップ 1 の CREATE LOGIN を実行
Cannot open database <DB> requested by the login. The login failed.ログインはあるが DB ユーザーがないステップ 2 の CREATE USER … FOR LOGIN …
User, group, or role ‘<name>’ already exists in the current database.同名ユーザーが既にあるALTER USER [<name>] WITH LOGIN = [<login>]; で再ひも付け
The server principal ‘<name>’ already exists.ログインは既に存在無視して次へ進むか、冪等スクリプトを使用
Permission denied in database ‘<DB>’必要ロール不足db_datareader/db_datawriter、必要に応じ GRANT EXECUTE を付与
Login is from an untrusted domain…クロスドメインで信頼関係なし同一ドメイン/信頼済みドメインのアカウントを使用

どの主体名を作ればいい?(早見表)

IIS 側の設定SQL Server に作成するログイン名備考
ApplicationPoolIdentity(既定)IIS APPPOOL\<AppPool名>本記事のメインパターン
NetworkServiceNT AUTHORITY\NETWORK SERVICEサーバー全体で共有されうる
LocalSystemNT AUTHORITY\SYSTEM権限が強すぎるため通常は非推奨
特定ユーザー(ドメイン/ローカル)DOMAIN\User または ServerName\Userサービス アカウントの管理が必要

実例(値を埋めたサンプル)

アプリプール名 MyWebPool、データベース MyAppDb の場合:

sqlcmd -S .\SQLEXPRESS -E -Q "CREATE LOGIN [IIS APPPOOL\MyWebPool] FROM WINDOWS;"
sqlcmd -S .\SQLEXPRESS -E -d MyAppDb -Q "CREATE USER [IIS APPPOOL\MyWebPool] FOR LOGIN [IIS APPPOOL\MyWebPool];"
sqlcmd -S .\SQLEXPRESS -E -d MyAppDb -Q "ALTER ROLE db_datareader ADD MEMBER [IIS APPPOOL\MyWebPool];"
sqlcmd -S .\SQLEXPRESS -E -d MyAppDb -Q "ALTER ROLE db_datawriter ADD MEMBER [IIS APPPOOL\MyWebPool];"

運用とセキュリティの注意点

  • 最小権限:安易に db_owner を付けない。DDL が必要な初期化処理は移行ツールで行い、アプリ本番は SELECT/INSERT/UPDATE/DELETE/EXECUTE のみに抑制。
  • 接続プール:権限追加後はアプリ再起動(リサイクル)で古いプールを解放。iisreset またはプールの停止→開始。
  • 監査:主体をアプリプール単位に分けると監査ログで「どのサイトからの操作か」が追跡しやすい。
  • 暗号化:開発環境では TrustServerCertificate=True で回避可能だが、本番は適切なサーバー証明書を導入。
  • バックアップ:SSMS がなくても sqlcmd でバックアップは実行可(例:BACKUP DATABASE)。

チェックリスト(5分で原因切り分け)

  1. 主体の確認:アプリ内で WindowsIdentity.GetCurrent().Name をログ出力し、IIS 実行時の主体を把握。
  2. ログイン存在:sys.server_principals に主体があるか。
  3. DB ユーザー存在:sys.database_principals に主体があるか。
  4. ロール付与:必要ロールが付いているか。
  5. 接続文字列:統合認証になっているか、DB 名の誤りはないか。

トラブル応用編(スクリプト断片)

既存ユーザーのログイン再ひも付け:

sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "ALTER USER [IIS APPPOOL\&lt;YourAppPoolName&gt;] WITH LOGIN = [IIS APPPOOL\&lt;YourAppPoolName&gt;];"

不要になったユーザー/ログインの削除:

sqlcmd -S .\SQLEXPRESS -E -d &lt;YourDatabase&gt; -Q "DROP USER IF EXISTS [IIS APPPOOL\&lt;YourAppPoolName&gt;];"
sqlcmd -S .\SQLEXPRESS -E -Q "DROP LOGIN IF EXISTS [IIS APPPOOL\&lt;YourAppPoolName&gt;];"

補足:ネットワークやファイアウォールは今回の主因ではない

同一マシン上の IIS → SQL Server Express で発生する「IIS のみ失敗」は、ほぼ必ず認証・権限設定の問題です。リモート接続(他サーバーからの接続)を計画している場合のみ、TCP 1433 の開放や SQL Server Browser/動的ポートの設計が論点になります。

補足:SQL Server Express の仕様を踏まえた設計

  • 1 DB あたり容量上限(一般的に 10GB 程度)を意識。
  • 同一サーバーに複数サイトが同居する場合は、アプリプールを分け、主体もプール単位で別々に作ると安全。
  • メンテナンス作業(インデックス再構築や統計更新)はアプリの主体ではなく、専用の管理者ジョブで行う。

まとめ

  • 鍵は「IIS が使う Windows アカウント(アプリケーション プール ID)を SQL Server に登録し、DB ユーザーとロールを正しく付与する」こと。
  • SSMS なしでも sqlcmd で完結:ログイン作成 → ユーザー作成 → ロール付与 → 確認の4手順。
  • 最小権限と主体分離を徹底すれば、セキュアで扱いやすい運用になる。

コピペ用:最小構成スクリプト(完成版)

@echo off
setlocal
set S=.\SQLEXPRESS
set DB=<YourDatabase>
set APPPOOL=<YourAppPoolName>

rem 1) ログイン(サーバー主体)
sqlcmd -S %S% -E -Q "IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE name = N'IIS APPPOOL%APPPOOL%') CREATE LOGIN [IIS APPPOOL%APPPOOL%] FROM WINDOWS;"

rem 2) データベース ユーザー
sqlcmd -S %S% -E -d %DB% -Q "IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = N'IIS APPPOOL%APPPOOL%') CREATE USER [IIS APPPOOL%APPPOOL%] FOR LOGIN [IIS APPPOOL%APPPOOL%];"

rem 3) 最低限ロール
sqlcmd -S %S% -E -d %DB% -Q "IF NOT EXISTS (SELECT 1 FROM sys.database_role_members m JOIN sys.database_principals r ON m.role_principal_id=r.principal_id JOIN sys.database_principals u ON m.member_principal_id=u.principal_id WHERE r.name='db_datareader' AND u.name=N'IIS APPPOOL%APPPOOL%') ALTER ROLE db_datareader ADD MEMBER [IIS APPPOOL%APPPOOL%];"
sqlcmd -S %S% -E -d %DB% -Q "IF NOT EXISTS (SELECT 1 FROM sys.database_role_members m JOIN sys.database_principals r ON m.role_principal_id=r.principal_id JOIN sys.database_principals u ON m.member_principal_id=u.principal_id WHERE r.name='db_datawriter' AND u.name=N'IIS APPPOOL%APPPOOL%') ALTER ROLE db_datawriter ADD MEMBER [IIS APPPOOL%APPPOOL%];"

rem 4) 確認
sqlcmd -S %S% -E -Q "SELECT 'server_principal' AS scope, name, type_desc FROM sys.server_principals WHERE name=N'IIS APPPOOL%APPPOOL%';"
sqlcmd -S %S% -E -d %DB% -Q "SELECT 'database_principal' AS scope, name, type_desc FROM sys.database_principals WHERE name=N'IIS APPPOOL%APPPOOL%';"
endlocal 

最後に:IIS 側で確認したいポイント

  • 対象サイトが「正しいアプリケーション プール」を使用していること。
  • そのプールの ID が意図通り(ApplicationPoolIdentity 等)であること。
  • 権限付与後にプールを再起動していること。

FAQ(簡易)

Q. SSMS を入れずに運用し続けられますか?
A. 可能です。ユーザー/ロール/バックアップ/復元/DDL はすべて sqlcmd で実行できます。とはいえ、保守性と可視化の観点で GUI を併用できる状態にしておくと確認作業が速くなります。

Q. 接続がときどき失敗します。
A. ログイン・ユーザー・ロールが揃っていても、古い接続プールが残ると新権限が反映されないことがあります。プールのリサイクル、アプリケーションの再起動を行ってください。

Q. 別サーバーの SQL Server に接続します。
A. クロスサーバーでは SPN/Kerberos、ポート、ファイアウォール、信頼関係など追加論点が生じます。本稿の主因(主体未登録)に加え、TCP/暗号化/証明書の整備もあわせて確認してください。


この記事の要点(1枚表)

やることコマンド例確認観点
ログイン作成CREATE LOGIN [IIS APPPOOL\<Pool>] FROM WINDOWS;sys.server_principals
DB ユーザー作成CREATE USER [IIS APPPOOL\<Pool>] FOR LOGIN […]sys.database_principals
ロール付与ALTER ROLE db_datareader/db_datawriter ADD MEMBER […]権限不足エラーの有無
接続文字列Trusted_Connection=True;TrustServerCertificate=True;統合認証・暗号化の扱い

以上で、IIS でもコマンド実行時と同じ主体で SQL Server に正しく認証・認可され、接続エラーは解消します。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次