InfraRunBook
    Back to articles

    FortiGate SSL-VPN User Cannot Connect

    Fortinet
    Published: Apr 19, 2026
    Updated: Apr 19, 2026

    A senior engineer's troubleshooting guide for FortiGate SSL-VPN connection failures, covering realm mismatches, IP pool exhaustion, split tunneling, certificate trust problems, and two-factor auth issues with real CLI commands.

    FortiGate SSL-VPN User Cannot Connect

    Symptoms

    SSL-VPN connection failures don't always announce themselves clearly. The symptoms depend on where in the handshake things break down, and I've seen everything from hard authentication errors to silent timeouts that leave users staring at a spinning FortiClient icon with no useful feedback.

    The most common things users report:

    • FortiClient displays "Unable to establish the VPN connection" or "Login failed" immediately after entering credentials
    • The web portal at
      https://vpn.solvethenetwork.com
      loads but after authentication redirects to a blank page or shows "No portal available"
    • The tunnel appears to connect — the lock icon in FortiClient turns green — but no internal resources are reachable
    • A two-factor prompt never appears, or the OTP code is consistently rejected even when entered correctly
    • Connection works for most users but fails for one specific user or one specific group
    • A certificate warning appears in the browser before the login page even loads

    Each of these failure modes points to a different layer of the SSL-VPN stack. Let's walk through the most likely culprits, starting with the ones that are easiest to miss because they produce misleading error messages.


    Root Cause 1: Realm Not Matching

    Why It Happens

    FortiGate SSL-VPN portals are tied to realms — URL path prefixes that determine which portal and authentication profile a connecting user lands on. The default realm is the root path (

    /
    ), but many organizations configure named realms like
    /remote
    or
    /contractors
    to segregate user populations. When a user hits the wrong URL — or when an admin renames a realm without updating the FortiClient profile pushed to endpoints — the FortiGate either presents the wrong portal or returns a login failure with no actionable error message.

    In my experience, this bites hardest after SSL-VPN URL migrations. Half the team connects fine because their FortiClient profile was updated; the other half gets a blank portal or a generic login error because their saved profile still points to an old realm path. The maddening part is that their credentials are correct — the realm routing is what's broken.

    How to Identify It

    Check the configured realms on the FortiGate CLI and compare them against your portal-to-group authentication rules:

    sw-infrarunbook-01 # config vpn ssl web realm
    sw-infrarunbook-01 (realm) # show
    config vpn ssl web realm
        edit "contractors"
            set url-path "/contractors"
            set virtual-host ""
        next
        edit ""
            set url-path "/"
        next
    end
    sw-infrarunbook-01 # config vpn ssl settings
    sw-infrarunbook-01 (settings) # show
    config vpn ssl settings
        set servercert "solvethenetwork-ssl-cert"
        set tunnel-ip-pools "SSLVPN_TUNNEL_ADDR1"
        set dns-server1 10.10.1.10
        set port 443
        config authentication-rule
            edit 1
                set groups "SSL-VPN-Users"
                set portal "full-access"
                set realm "contractors"
            next
        end
    end

    Then pull the event log. A realm mismatch produces a very specific log entry:

    sw-infrarunbook-01 # execute log filter category 1
    sw-infrarunbook-01 # execute log filter field action login
    sw-infrarunbook-01 # execute log display
    
    date=2026-04-19 time=09:14:22 logid="0101037127" type="event" subtype="vpn"
    level="error" action="ssl-login-fail" reason="sslvpn_login_unknown_user"
    user="infrarunbook-admin" realm="" profile="no-access"
    msg="SSL user failed to login"

    The

    realm=""
    field combined with
    profile="no-access"
    is the tell — the user hit the root URL but no authentication rule maps their group to a portal under that realm.

    How to Fix It

    Either update the FortiClient profile on affected machines to point at the correct realm URL, or add the user's group to an authentication rule that covers the realm they're hitting. To map a group to the default (root) realm:

    sw-infrarunbook-01 # config vpn ssl settings
    sw-infrarunbook-01 (settings) # config authentication-rule
    sw-infrarunbook-01 (authentication-rule) # edit 2
    sw-infrarunbook-01 (2) # set groups "SSL-VPN-Users"
    sw-infrarunbook-01 (2) # set portal "full-access"
    sw-infrarunbook-01 (2) # set realm ""
    sw-infrarunbook-01 (2) # end

    No service interruption for existing sessions — realm rule changes take effect for new connections only.


    Root Cause 2: IP Pool Exhausted

    Why It Happens

    Every SSL-VPN tunnel client gets a virtual IP address assigned from a tunnel IP pool. The default pool —

    SSLVPN_TUNNEL_ADDR1
    — ships from the factory with a range of ten addresses (typically something like 10.212.134.200–10.212.134.209). In a small office that's adequate. Scale past ten concurrent VPN users and the pool empties. New connection attempts fail because the FortiGate has no IP to assign, and the error users see is a generic login failure with absolutely no indication of the real problem.

    This one catches administrators off guard because everything works perfectly right up until the eleventh simultaneous connection. It's also easy to dismiss as an intermittent issue because the pool drains and fills throughout the day — a morning standup where everyone connects at once is a classic trigger, and by the time someone investigates, a few users have disconnected and the pool looks fine again.

    How to Identify It

    Check current active tunnel sessions against the pool capacity:

    sw-infrarunbook-01 # diagnose vpn ssl list
    
    SSL VPN Login Users:
    Index   User                  Auth-Type  Timeout  From            HTTP in/out  HTTPS in/out
    0       infrarunbook-admin    1          290      10.50.0.15      0/0          2/0
    1       jsmith                1          288      10.50.0.22      0/0          1/0
    2       mlopez                1          285      10.50.0.31      0/0          1/0
    ...
    Total: 10 users
    sw-infrarunbook-01 # diagnose firewall ippool-all list
    
    name: SSLVPN_TUNNEL_ADDR1
    type: overload
    startip: 10.212.134.200
    endip: 10.212.134.209
    total: 10
    used: 10
    free: 0

    free: 0
    is your answer. This will also appear in the event log with a clear reason code:

    date=2026-04-19 time=09:31:05 logid="0101037146" type="event" subtype="vpn"
    level="error" action="tunnel-down" reason="ip-pool-empty"
    user="bwilliams" msg="SSL VPN tunnel interface IP allocation failed"

    How to Fix It

    Expand the tunnel IP pool. The subnet must not overlap with any existing interface or routing table entry on the FortiGate:

    sw-infrarunbook-01 # config firewall address
    sw-infrarunbook-01 (address) # edit "SSLVPN_TUNNEL_ADDR1"
    sw-infrarunbook-01 (SSLVPN_TUNNEL_ADDR1) # set type iprange
    sw-infrarunbook-01 (SSLVPN_TUNNEL_ADDR1) # set start-ip 10.212.134.200
    sw-infrarunbook-01 (SSLVPN_TUNNEL_ADDR1) # set end-ip 10.212.134.254
    sw-infrarunbook-01 (SSLVPN_TUNNEL_ADDR1) # end

    That takes the pool from 10 to 55 addresses without touching existing sessions. If you need more room, create a second pool object and add it to the SSL-VPN settings under

    tunnel-ip-pools
    . No reboot, no service disruption.


    Root Cause 3: Split Tunneling Misconfigured

    Why It Happens

    Split tunneling controls which traffic from the VPN client actually routes through the tunnel versus out the user's local internet connection. When it's wrong, users connect successfully — FortiClient shows the tunnel as green — but then either can't reach internal resources because the target subnet isn't in the routing address list, or find that all their internet traffic breaks because the portal is in full-tunnel mode when split tunnel was expected. Both scenarios manifest as "the VPN doesn't work" even though the VPN itself is functioning correctly.

    The misconfiguration usually creeps in one of two ways: a new internal subnet goes live but nobody updates the SSL-VPN portal's routing addresses, or a portal gets accidentally toggled to full-tunnel mode during an upgrade or config restore.

    How to Identify It

    Pull the portal configuration and inspect the split tunneling settings:

    sw-infrarunbook-01 # config vpn ssl web portal
    sw-infrarunbook-01 (portal) # edit "full-access"
    sw-infrarunbook-01 (full-access) # show
    config vpn ssl web portal
        edit "full-access"
            set tunnel-mode enable
            set web-mode enable
            set split-tunneling enable
            set split-tunneling-routing-address "Internal_Subnets" "DMZ_Servers"
            set ip-pools "SSLVPN_TUNNEL_ADDR1"
        next
    end

    Then verify what subnets are actually inside those address objects:

    sw-infrarunbook-01 # show firewall addrgrp "Internal_Subnets"
    config firewall addrgrp
        edit "Internal_Subnets"
            set member "10.10.1.0/24" "10.10.2.0/24"
        next
    end

    If the user is trying to reach 10.10.5.0/24 — the storage VLAN that was added last month — and it's not in that group, traffic to it bypasses the tunnel entirely and hits the user's default gateway instead. You can confirm this from the client side with a

    route print
    (Windows) or
    ip route show
    (Linux) while connected: the missing subnet won't appear under the tunnel interface.

    For the opposite problem — full tunnel when split was expected — one field tells the whole story:

    sw-infrarunbook-01 (full-access) # get | grep split
    split-tunneling             : disable

    That single line explains an entire category of "internet stopped working when I connected to VPN" tickets.

    How to Fix It

    Add the missing subnets to the routing address group and correct the split tunneling flag:

    sw-infrarunbook-01 # config firewall addrgrp
    sw-infrarunbook-01 (addrgrp) # edit "Internal_Subnets"
    sw-infrarunbook-01 (Internal_Subnets) # set member "10.10.1.0/24" "10.10.2.0/24" "10.10.5.0/24"
    sw-infrarunbook-01 (Internal_Subnets) # end
    sw-infrarunbook-01 # config vpn ssl web portal
    sw-infrarunbook-01 (portal) # edit "full-access"
    sw-infrarunbook-01 (full-access) # set split-tunneling enable
    sw-infrarunbook-01 (full-access) # end

    Already-connected users will need to disconnect and reconnect to receive the updated routing table pushed by the portal on tunnel establishment.


    Root Cause 4: Certificate Not Trusted

    Why It Happens

    FortiGate ships with a self-signed certificate for its HTTPS interface. Most organizations replace this with a certificate issued by an internal CA or a public CA. When the certificate chain isn't trusted by the connecting client — because it's still self-signed, because the CA root hasn't been deployed to endpoints, or because a certificate expired — FortiClient either refuses the connection outright or presents a warning that confuses non-technical users into abandoning the attempt.

    The sneaky variant I see most often is an expired intermediate certificate. The root CA is trusted, the end-entity certificate is valid, but an intermediate in the chain expired and wasn't renewed. The OpenSSL validation fails at the intermediate, the user sees a generic TLS error, and nobody immediately thinks to check intermediate expiry.

    How to Identify It

    Start by confirming which certificate the FortiGate is presenting for SSL-VPN:

    sw-infrarunbook-01 # config vpn ssl settings
    sw-infrarunbook-01 (settings) # get | grep servercert
    servercert                  : solvethenetwork-ssl-cert

    Then verify the certificate's chain from an external host using OpenSSL:

    openssl s_client -connect vpn.solvethenetwork.com:443 -showcerts
    
    CONNECTED(00000003)
    depth=0 CN=*.solvethenetwork.com
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    ---
    Certificate chain
     0 s:CN=*.solvethenetwork.com
       i:CN=SolveTheNetwork Internal CA
    ---
    No client certificate CA names sent
    SSL handshake has read 2143 bytes and written 0 bytes
    Verify return code: 20 (unable to get local issuer certificate)

    Return code 20 means the issuer certificate isn't in the presented chain — the FortiGate is sending the end-entity cert but not the intermediate, so clients that don't already have the intermediate cached can't validate the chain. You can also check certificate expiry directly:

    openssl s_client -connect vpn.solvethenetwork.com:443 2>/dev/null | openssl x509 -noout -dates
    
    notBefore=Mar  1 00:00:00 2025 GMT
    notAfter=Mar  1 23:59:59 2026 GMT

    How to Fix It

    For a publicly-facing portal, the cleanest fix is a certificate from a publicly trusted CA. For internal CA scenarios, ensure the full chain including intermediates is imported into the FortiGate and bound to the SSL-VPN service certificate. When importing, bundle the intermediate with the end-entity cert in the same PEM file. Then push the CA root to all managed endpoints via Group Policy or your MDM platform so validation works without manual certificate installation on every client machine.

    To bind the corrected certificate to SSL-VPN:

    sw-infrarunbook-01 # config vpn ssl settings
    sw-infrarunbook-01 (settings) # set servercert "solvethenetwork-ssl-cert-fullchain"
    sw-infrarunbook-01 (settings) # end

    Root Cause 5: Two-Factor Authentication Issue

    Why It Happens

    FortiGate supports multiple 2FA mechanisms for SSL-VPN: FortiToken hardware or mobile app, email OTP, SMS OTP via FortiAuthenticator, or RADIUS-delivered OTP from a third-party MFA provider like Duo or Microsoft NPS. Any broken link in this chain results in the second factor never arriving or always being rejected — and the error message the user sees gives almost no indication of which link failed.

    FortiToken clock drift is the one I encounter most in production. FortiToken Mobile generates TOTP codes tied to the phone's system clock. If that clock drifts more than 60 seconds from the FortiGate's reference time, the generated codes will never match what the FortiGate expects, even though the user is entering them correctly and promptly.

    How to Identify It

    Check the FortiToken status and drift value:

    sw-infrarunbook-01 # diagnose user fortitoken status FTK123456789
    
    Token serial: FTK123456789
    Token status: active
    User        : infrarunbook-admin
    Clock drift : +127 seconds

    A drift of 127 seconds is why every code fails — the FortiGate and the token app are over two minutes apart. For email OTP, test the SMTP relay directly from the FortiGate:

    sw-infrarunbook-01 # config system email-server
    sw-infrarunbook-01 (email-server) # show
    config system email-server
        set reply-to "noreply@solvethenetwork.com"
        set server "10.10.1.25"
        set port 25
        set auth-type none
    end
    
    sw-infrarunbook-01 # diagnose sys email test noreply@solvethenetwork.com

    If the test email doesn't arrive, the SMTP relay is the problem — not the VPN. Check the relay server's mail logs and verify that port 25 isn't being blocked between the FortiGate management IP and the relay. For FortiAuthenticator-backed RADIUS 2FA, test the full authentication path:

    sw-infrarunbook-01 # diagnose test auth radius FortiAuthenticator pap infrarunbook-admin Password123 654321
    
    Authenticate 'infrarunbook-admin' against 'FortiAuthenticator' succeeded

    A timeout response here means the FortiGate can't reach the FortiAuthenticator on UDP/1812 — check routing and ACLs. A reject response with

    reason=invalid OTP
    means the user or token is misconfigured on the FortiAuthenticator side.

    How to Fix It

    For FortiToken clock drift, the correction command is straightforward:

    sw-infrarunbook-01 # execute fortitoken-drift-correction FTK123456789
    
    FortiToken FTK123456789 drift corrected successfully.

    This adjusts the FortiGate's expected offset for that specific token without requiring the user to re-enroll. For email OTP, resolve the SMTP relay issue or switch to an authenticated relay with TLS if the current relay is rejecting unauthenticated connections. For FortiAuthenticator RADIUS, verify that the RADIUS shared secret matches on both sides and that the FortiGate's source IP is listed as an authorized NAS client in the FortiAuthenticator admin console. If the user's local account isn't configured for the correct 2FA method, fix it directly:

    sw-infrarunbook-01 # config user local
    sw-infrarunbook-01 (local) # edit "infrarunbook-admin"
    sw-infrarunbook-01 (infrarunbook-admin) # set two-factor fortitoken
    sw-infrarunbook-01 (infrarunbook-admin) # set fortitoken "FTK123456789"
    sw-infrarunbook-01 (infrarunbook-admin) # set email-to "admin@solvethenetwork.com"
    sw-infrarunbook-01 (infrarunbook-admin) # end

    Root Cause 6: User Group Not Mapped to a Portal

    Why It Happens

    A user can authenticate successfully — correct password, correct 2FA code — and still be refused or land on a blank portal because their group isn't referenced in any SSL-VPN authentication rule. FortiGate's portal assignment is entirely group-driven. If someone is placed in the wrong LDAP group, or if the local user group on the FortiGate doesn't include the user, the FortiGate has no portal to hand them and the session is dropped.

    This is common after LDAP group restructuring. An admin reorganizes AD groups for a department move but doesn't update the SSL-VPN authentication rules to reference the new group names. The users authenticate fine at the directory level but get blocked at the portal assignment step.

    How to Identify It

    The log entry is usually unambiguous:

    date=2026-04-19 time=10:44:11 logid="0101037130" type="event" subtype="vpn"
    level="warning" action="ssl-login-fail" reason="sslvpn_login_permission_denied"
    user="infrarunbook-admin" group="N/A" portal="N/A"
    msg="User does not belong to any SSL VPN portal group"

    group="N/A"
    and
    portal="N/A"
    confirm that authentication succeeded but group resolution failed. Test LDAP group membership directly from the CLI:

    sw-infrarunbook-01 # diagnose test authserver ldap LDAP_Server infrarunbook-admin Password123
    
    authenticate 'infrarunbook-admin' against 'LDAP_Server' succeeded!
    Group membership(s) - CN=HelpDesk,OU=Groups,DC=solvethenetwork,DC=com

    The user is a member of

    HelpDesk
    in LDAP, but the SSL-VPN authentication rules only reference
    SSL-VPN-Users
    . That's the gap. The user authenticated but fell through all rules with no match.

    How to Fix It

    Add the

    HelpDesk
    group to an authentication rule, either the existing one or a new rule pointing to an appropriate portal:

    sw-infrarunbook-01 # config vpn ssl settings
    sw-infrarunbook-01 (settings) # config authentication-rule
    sw-infrarunbook-01 (authentication-rule) # edit 3
    sw-infrarunbook-01 (3) # set groups "HelpDesk"
    sw-infrarunbook-01 (3) # set portal "limited-access"
    sw-infrarunbook-01 (3) # set realm ""
    sw-infrarunbook-01 (3) # end

    Root Cause 7: Firewall Policy Missing for SSL-VPN Traffic

    Why It Happens

    The tunnel comes up, the user gets an IP from the pool, split tunneling is configured correctly — but nothing inside the network is reachable. This almost always means a missing or incorrectly scoped firewall policy. Traffic from the SSL-VPN interface (

    ssl.root
    ) to internal zones requires an explicit allow policy. FortiOS does not create this automatically when SSL-VPN is enabled. It's a manual step that's easy to skip, especially when building a new FortiGate from scratch or after restoring a partial configuration backup.

    How to Identify It

    Check whether any policy exists with

    ssl.root
    as the source interface:

    sw-infrarunbook-01 # show firewall policy | grep -B2 ssl.root
    
    edit 10
        set name "SSL-VPN to Internal"
        set srcintf "ssl.root"

    If that returns nothing, there's no policy. You can also use the built-in iprope lookup to simulate a specific traffic flow:

    sw-infrarunbook-01 # diagnose firewall iprope lookup 10.212.134.201 10.10.1.100 6 443 0 ssl.root
    
    Matched policy id: 0 (no matching policy found)

    Policy ID 0 means implicit deny — traffic from the VPN pool hitting port 443 on an internal host has no permit rule.

    How to Fix It

    Create the policy. Scope it to the tunnel address pool as the source and whatever internal resources VPN users should reach as the destination:

    sw-infrarunbook-01 # config firewall policy
    sw-infrarunbook-01 (policy) # edit 10
    sw-infrarunbook-01 (10) # set name "SSL-VPN to Internal"
    sw-infrarunbook-01 (10) # set srcintf "ssl.root"
    sw-infrarunbook-01 (10) # set dstintf "internal"
    sw-infrarunbook-01 (10) # set srcaddr "SSLVPN_TUNNEL_ADDR1"
    sw-infrarunbook-01 (10) # set dstaddr "Internal_Subnets"
    sw-infrarunbook-01 (10) # set action accept
    sw-infrarunbook-01 (10) # set schedule "always"
    sw-infrarunbook-01 (10) # set service "ALL"
    sw-infrarunbook-01 (10) # set logtraffic all
    sw-infrarunbook-01 (10) # end

    The change takes effect immediately. Existing tunnel sessions that were already connected will start routing correctly without needing to reconnect.


    Prevention

    Most of these issues are repeatable and preventable. The realm and portal mapping problems almost always come from changes made without a checklist. Someone restructures an AD group, forgets to update the SSL-VPN authentication rule, and discovers the gap two weeks later when a user calls the helpdesk. Maintaining a simple runbook that maps every user group to its expected realm and portal — and making that runbook a required review step for any directory change — closes that gap.

    IP pool exhaustion is easy to get ahead of. Set a monitoring threshold: if active SSL-VPN sessions exceed 70% of your pool capacity, trigger an alert. FortiGate exposes active session counts via SNMP, and any NMS worth running can graph this and page you before you hit saturation. Don't wait for users to report it — by then the pool is already full.

    For certificates, calendar the expiry dates and build in 30-day lead time for renewal. A week of runway isn't enough when you factor in change control windows. If you're using an ACME provider, automate both the renewal and the import to FortiGate using the REST API — the FortiGate supports certificate management via API endpoints and it's worth the one-time automation investment.

    FortiToken clock drift is best caught proactively. A weekly script that runs

    diagnose user fortitoken status
    across all enrolled tokens and alerts if drift exceeds 30 seconds gives you time to correct it before it starts rejecting codes. The correction command is non-disruptive and takes seconds.

    Split tunnel routing address groups should be part of your subnet provisioning checklist — not an afterthought. When a new VLAN is created and a subnet is assigned, adding it to the SSL-VPN portal routing addresses should be a required step, the same as adding a firewall policy for it. Treat the portal routing list the same way you treat your routing table: it needs to be updated when the network changes.

    Finally, always validate SSL-VPN configuration changes with a test account before rolling them out to a production group. A five-minute connection test from a clean machine — not your own workstation with a cached session — catches the majority of the issues above. The cost of that test is negligible. The cost of fifty people unable to work from home while you debug a realm misconfiguration is not.

    Frequently Asked Questions

    Why does FortiClient say 'Login failed' even when the username and password are correct?

    Several issues can cause this despite valid credentials: the user's group may not be mapped to any SSL-VPN portal in the authentication rules, the user may be connecting to the wrong realm URL, or the tunnel IP pool may be exhausted. Check the FortiGate event log with 'execute log display' after filtering for VPN events — the reason field will usually pinpoint the cause exactly.

    How do I check how many SSL-VPN users are currently connected on FortiGate?

    Run 'diagnose vpn ssl list' from the FortiGate CLI. This shows all active tunnel sessions with usernames, source IPs, and session timers. To see IP pool utilization alongside it, run 'diagnose firewall ippool-all list' and check the 'used' and 'free' counters for SSLVPN_TUNNEL_ADDR1.

    What does 'realm' mean in FortiGate SSL-VPN and how does it affect login?

    A realm is a URL path prefix (like /contractors or /) that determines which portal and authentication rules apply to a connecting user. If a user's FortiClient profile points to a URL path that doesn't match any configured realm, or if their group isn't mapped to an authentication rule for that realm, they'll receive a login failure even with valid credentials.

    FortiClient shows the VPN as connected but I can't reach any internal servers — why?

    Two likely causes: first, split tunneling routing addresses may be missing the subnet you're trying to reach — check the portal's split-tunneling-routing-address configuration and verify the target subnet is included. Second, there may be no firewall policy permitting traffic from ssl.root to the internal interface. Use 'diagnose firewall iprope lookup' to test whether a matching policy exists for the specific source/destination pair.

    How do I fix FortiToken codes that are always rejected for a specific user?

    Run 'diagnose user fortitoken status <serial>' to check the clock drift value for that token. If drift exceeds 60 seconds, run 'execute fortitoken-drift-correction <serial>' to resync the token without requiring the user to re-enroll. Also verify the user's local account is configured with the correct token serial under 'config user local' and that the two-factor method is set to fortitoken.

    Related Articles