What Is iSCSI and When to Use It?

iSCSI (Internet Small Computer System Interface) is a block storage protocol that transports SCSI commands over standard TCP/IP networks. It allows Windows servers to access remote SAN (Storage Area Network) storage arrays as if they were locally attached block devices. Unlike NAS (Network Attached Storage) which presents file-level access over SMB or NFS, iSCSI presents raw block devices — you format them, assign drive letters, and use them exactly like any locally connected disk.

iSCSI is widely used for connecting to enterprise SAN arrays (NetApp, Dell EMC, Pure Storage, HPE, and others), software-defined storage systems (Windows Storage Spaces, TrueNAS, StarWind), and virtualization storage (Hyper-V CSV, VMware VMFS). Its key advantages are running over standard 1GbE, 10GbE, or 25GbE Ethernet without any specialized HBA hardware, and full integration with Windows Disk Management and PowerShell storage cmdlets.

The terminology: the iSCSI Initiator is the Windows Server connecting to storage. The iSCSI Target is the storage array or server presenting the storage. LUNs (Logical Unit Numbers) are the individual block storage volumes presented by the target. The Target IQN (iSCSI Qualified Name) is the unique identifier of a target in the format iqn.YYYY-MM.com.company:storage-name.

Starting the iSCSI Initiator Service

Windows Server 2022 includes the Microsoft iSCSI Initiator built in, but the service is set to Manual start by default. Before connecting to any iSCSI target, start and enable the service:

# Start the iSCSI service and set to automatic
Start-Service MSiSCSI
Set-Service MSiSCSI -StartupType Automatic

# Verify service is running
Get-Service MSiSCSI | Select-Object Name, Status, StartType

The iSCSI Initiator GUI can also be launched from Server Manager (Tools > iSCSI Initiator) or directly:

iscsicpl.exe

On first launch, Windows prompts to start the MSiSCSI service automatically — clicking Yes enables the service. The Initiator Name (IQN) for this server is shown on the Configuration tab of iscsicpl.exe. Note this value — you will need it when configuring access controls on the target side:

# Get initiator IQN via PowerShell
(Get-InitiatorPort).NodeAddress

Configuring the Target Portal

A Target Portal is the IP address and TCP port (default 3260) of the iSCSI target interface you want to connect to. Add target portals to tell the initiator where to look for iSCSI targets:

# Add an iSCSI target portal
New-IscsiTargetPortal -TargetPortalAddress "192.168.100.10" -TargetPortalPortNumber 3260

# If using a specific initiator NIC for iSCSI traffic
New-IscsiTargetPortal -TargetPortalAddress "192.168.100.10" `
    -InitiatorPortalAddress "192.168.100.50"  # Local NIC IP for iSCSI

# View configured target portals
Get-IscsiTargetPortal | Select-Object TargetPortalAddress, TargetPortalPortNumber, 
    InitiatorPortalAddress

After adding the portal, discover what targets are available:

Get-IscsiTarget | Select-Object NodeAddress, IsConnected, IsPersistent

This lists all iSCSI targets discovered from configured portals. The NodeAddress is the target’s IQN. If no targets appear, verify network connectivity to the target portal IP on port 3260:

Test-NetConnection -ComputerName 192.168.100.10 -Port 3260

Connecting to an iSCSI Target

Once targets are discovered, connect to the target IQN using Connect-IscsiTarget:

# Basic connection to a target
Connect-IscsiTarget -NodeAddress "iqn.2023-01.com.storage:array01-lun1"

# Persistent connection (reconnects after reboot)
Connect-IscsiTarget -NodeAddress "iqn.2023-01.com.storage:array01-lun1" `
    -IsPersistent $true

# Connection via specific initiator portal (for network isolation)
Connect-IscsiTarget -NodeAddress "iqn.2023-01.com.storage:array01-lun1" `
    -TargetPortalAddress "192.168.100.10" `
    -InitiatorPortalAddress "192.168.100.50" `
    -IsPersistent $true

Verify the connection was established:

Get-IscsiSession | Select-Object TargetNodeAddress, ConnectionIdentifier, 
    IsConnected, IsPersistent, NumberOfConnections

After a successful connection, Windows discovers the LUNs presented by that target and they appear as new disks in Disk Management (diskmgmt.msc) and in PowerShell:

Get-Disk | Where-Object { $_.BusType -eq "iSCSI" } | 
    Select-Object Number, FriendlyName, Size, PartitionStyle, OperationalStatus

CHAP Authentication

Challenge Handshake Authentication Protocol (CHAP) provides authentication between the initiator and target, preventing unauthorized initiators from connecting to iSCSI targets. There are two modes: one-way CHAP (target authenticates the initiator) and mutual CHAP (both sides authenticate each other).

Configure one-way CHAP on the initiator:

# Set CHAP credentials for connecting to a specific target
Connect-IscsiTarget -NodeAddress "iqn.2023-01.com.storage:array01-lun1" `
    -AuthenticationType "OneWayCHAP" `
    -ChapUsername "initiator-username" `
    -ChapSecret (ConvertTo-SecureString "CHAPsecret123!" -AsPlainText -Force) `
    -IsPersistent $true

For mutual CHAP, the target also presents credentials to the initiator. Configure this via the iSCSI Initiator GUI (iscsicpl.exe > Configuration > CHAP) or PowerShell:

Connect-IscsiTarget -NodeAddress "iqn.2023-01.com.storage:array01-lun1" `
    -AuthenticationType "MutualCHAP" `
    -ChapUsername "initiator-user" `
    -ChapSecret (ConvertTo-SecureString "InitiatorSecret!" -AsPlainText -Force) `
    -InitiatorChapSecret (ConvertTo-SecureString "TargetSecret!" -AsPlainText -Force) `
    -IsPersistent $true

CHAP secrets must be 12-16 characters. The same secret must be configured on the target side (in the SAN management interface). Note that CHAP over iSCSI transmits data in cleartext — for sensitive data, use iSCSI over an isolated VLAN or combine with IPsec for encryption in transit.

Installing MPIO for iSCSI

Multipath I/O (MPIO) is critical for iSCSI in production environments. It provides multiple physical paths to the same LUN for fault tolerance and load balancing. Without MPIO, a NIC failure or switch failure disconnects all iSCSI LUNs instantly, which causes data corruption in live VMs or databases.

Install the MPIO Windows Feature:

Install-WindowsFeature -Name "Multipath-IO" -IncludeManagementTools
# Reboot required after installation
Restart-Computer

After reboot, configure MPIO to automatically claim iSCSI devices. This is the most important step — without it, Windows will see each path as a separate disk rather than combining them:

# Enable automatic MPIO claiming for iSCSI devices
Enable-MSDSMAutomaticClaim -BusType iSCSI

# Verify the setting
Get-MSDSMAutomaticClaimSettings

Configure the MPIO load balancing policy. The default is Fail Over Only (one active path, others standby). For production workloads, Round Robin distributes I/O across all active paths:

# Set default load balancing policy
Set-MSDSMGlobalDefaultLoadBalancePolicy -Policy RR  # Round Robin

# Available policies: FOO (Fail Over Only), RR (Round Robin), 
# RRWS (Round Robin with Subset), LQD (Least Queue Depth), WP (Weighted Paths)

# View MPIO path status for connected disks
Get-MSDSMAvailableHW | Select-Object VendorId, ProductId

# Check paths for a specific disk
$disk = Get-Disk | Where-Object { $_.BusType -eq "iSCSI" } | Select-Object -First 1
Get-StorageReliabilityCounter -Disk $disk

For iSCSI MPIO to work properly, you need two separate iSCSI connections to the same target — each using a different initiator NIC and a different target portal IP. Set this up by connecting to the target twice with different interface bindings:

# First path: NIC1 to Target portal 1
Connect-IscsiTarget -NodeAddress "iqn.2023-01.com.storage:array01-lun1" `
    -TargetPortalAddress "192.168.100.10" `
    -InitiatorPortalAddress "192.168.100.50" `
    -IsMultipathEnabled $true -IsPersistent $true

# Second path: NIC2 to Target portal 2  
Connect-IscsiTarget -NodeAddress "iqn.2023-01.com.storage:array01-lun1" `
    -TargetPortalAddress "192.168.101.10" `
    -InitiatorPortalAddress "192.168.101.50" `
    -IsMultipathEnabled $true -IsPersistent $true

iSCSI Network Isolation

iSCSI storage traffic should always run on a dedicated network, separate from production data traffic and management traffic. Mixing iSCSI with regular Ethernet traffic risks bandwidth saturation dropping the iSCSI connection, causing disk I/O errors or even data corruption in running VMs.

Best practice is a dedicated iSCSI VLAN (commonly VLAN 300 or VLAN 400 in enterprise networks) with dedicated NICs assigned to that VLAN. If dedicated physical NICs are not available, use separate VLAN-tagged interfaces:

# Assign iSCSI NICs to dedicated VLAN
Set-NetAdapter -Name "iSCSI-NIC1" -VlanID 300
Set-NetAdapter -Name "iSCSI-NIC2" -VlanID 300

# Disable DNS registration and gateway on iSCSI NICs (storage only)
Set-DnsClient -InterfaceAlias "iSCSI-NIC1" -RegisterThisConnectionsAddress $false
Set-DnsClient -InterfaceAlias "iSCSI-NIC2" -RegisterThisConnectionsAddress $false

# Remove default gateway from iSCSI NICs (they should not route)
Remove-NetRoute -InterfaceAlias "iSCSI-NIC1" -DestinationPrefix "0.0.0.0/0" -Confirm:$false

Configure jumbo frames on iSCSI NICs and switches for improved throughput (standard Ethernet MTU of 1500 is inefficient for block storage):

Set-NetAdapterAdvancedProperty -Name "iSCSI-NIC1" -DisplayName "Jumbo Packet" -DisplayValue "9014 Bytes"
Set-NetAdapterAdvancedProperty -Name "iSCSI-NIC2" -DisplayName "Jumbo Packet" -DisplayValue "9014 Bytes"

Persistent Login and Favorite Targets

For the iSCSI LUN to reconnect automatically after a server reboot, mark the connection as persistent. PowerShell connections with -IsPersistent $true add the target to the Favorite Targets list in iscsicpl.exe. You can also manage Favorite Targets directly in the GUI (iSCSI Initiator > Favorite Targets tab).

View and manage persistent connections:

# View all persistent (favorite) targets
Get-IscsiTarget | Where-Object { $_.IsPersistent -eq $true } | 
    Select-Object NodeAddress, IsPersistent

# Remove a persistent target entry
Disconnect-IscsiTarget -NodeAddress "iqn.2023-01.com.storage:array01-lun1" `
    -SessionIdentifier (Get-IscsiSession -TargetNodeAddress "iqn.2023-01.com.storage:array01-lun1").SessionIdentifier
    
# Unregister from favorites
Unregister-IscsiSession -SessionIdentifier 

Formatting and Using the iSCSI Disk

Once connected, the iSCSI LUN appears as a new disk. Initialize, partition, and format it:

# Find the new iSCSI disk
$iscsiDisk = Get-Disk | Where-Object { $_.BusType -eq "iSCSI" -and $_.PartitionStyle -eq "RAW" }

# Initialize with GPT (required for disks over 2TB)
Initialize-Disk -Number $iscsiDisk.Number -PartitionStyle GPT

# Create a partition using all available space
$partition = New-Partition -DiskNumber $iscsiDisk.Number -UseMaximumSize -AssignDriveLetter

# Format with NTFS (or ReFS for large files and resiliency)
Format-Volume -DriveLetter $partition.DriveLetter -FileSystem NTFS `
    -NewFileSystemLabel "iSCSI-LUN1" -AllocationUnitSize 65536 -Confirm:$false

For SQL Server or Hyper-V workloads, use a 64 KB allocation unit size (65536 bytes) for better sequential I/O alignment. For general file storage, the default 4096-byte allocation unit is appropriate.

Troubleshooting iSCSI Connectivity

Target not discovered after adding portal: Verify the iSCSI target service is running on the storage array, that the initiator IQN is allowed in the target’s access control list (ACL), and that TCP 3260 is open in firewalls. Test explicitly:

Test-NetConnection -ComputerName 192.168.100.10 -Port 3260 -InformationLevel Detailed

Disk disconnects after reboot: The MSiSCSI service startup type must be Automatic (not Manual). Check with Get-Service MSiSCSI | Select-Object StartType. Also verify the target is in Favorite Targets in iscsicpl.exe.

I/O errors in Event Viewer: Check the System event log for iScsiPrt errors (Event Source: iScsiPrt). Event ID 1 indicates a session was terminated. This usually means network interruption. If using MPIO, verify both paths are active:

Get-IscsiSession | Select-Object TargetNodeAddress, ConnectionIdentifier, 
    IsConnected, NumberOfConnections

# Check Windows event log for iSCSI errors
Get-WinEvent -LogName System | 
    Where-Object { $_.ProviderName -eq "iScsiPrt" } |
    Select-Object -First 20 TimeCreated, Id, Message

iSCSI with VLANs not working: Ensure the VLAN tagging is configured consistently on both the NIC (Windows side) and the switch port. If using 802.1Q trunking, the switch port must be configured as a trunk with the iSCSI VLAN allowed and the NIC must have VLAN tagging enabled in its advanced properties. Also confirm the target array’s iSCSI interface is on the same VLAN.