<!-- https://pkizerotohero.com/guides/install-certificate-iis/ | Markdown mirror of the HTML page | PKI Zero to Hero, by Duyutech BV -->

> Install a TLS certificate in IIS: check and import the PFX, place the intermediate, add an HTTPS binding with SNI, verify the chain and plan renewal.

Source: https://pkizerotohero.com/guides/install-certificate-iis/ · Last reviewed: 2026-10-20

How-to guide · Install on a server

# How to install a certificate in IIS

**In one sentence:**

IIS serves your certificate with its private key and intermediate on an HTTPS binding with SNI, and renewed certificates get rebound instead of silently expiring.

Task

[Install on a server](https://pkizerotohero.com/guides/#task-install)

Platforms

- Windows
- IIS

Who it is for

- [IT ops](https://pkizerotohero.com/start/#itops)

Level

Practitioner · 5 steps

## Before you start

- Windows Server with IIS 10 (IIS 8.5 or later for automatic rebind), and an administrator account.
- Your certificate **with its private key**: a PFX (PKCS #12) file and its password, or the CA’s response to a CSR you created on this server ([create a CSR on Windows](https://pkizerotohero.com/guides/create-csr-windows/)).
- The CA’s [intermediate certificate](https://pkizerotohero.com/handbook/glossary/#intermediate-certificate), if the PFX does not contain it.
- For Let’s Encrypt, [win-acme](https://pkizerotohero.com/guides/win-acme-windows/) does all of this and keeps it renewed.

Why it matters: IIS refers to the certificate by thumbprint in the computer’s store, and Windows sends the chain it can build from that computer’s stores. A missing intermediate or private key is the usual cause of a broken HTTPS site on IIS.

## Steps

### 1. Check the PFX before you import it

`certutil -dump` reads the file without importing anything. For our test PFX, built with OpenSSL from a throwaway test CA, Windows 11 showed:

```powershell
certutil -dump -p <password> www.pfx
```

```text
================ Certificate 0 ================
Issuer: CN=Example Corp Root CA, O=Example Corp, C=BE
Subject: CN=Example Corp Issuing CA 1, O=Example Corp, C=BE
No key provider information
...
================ Certificate 1 ================
Issuer: CN=Example Corp Issuing CA 1, O=Example Corp, C=BE
Subject: CN=intranet.example.com
  Provider = Microsoft Software Key Storage Provider
Encryption test passed
CertUtil: -dump command completed successfully.
```

You want two things: the server certificate with a private key (`Encryption test passed`), and the intermediate. The intermediate has no key, which is correct. If you have PEM files instead, build the PFX with OpenSSL and include the intermediate with `-certfile`:

```bash
openssl pkcs12 -export -out www.pfx -inkey www.key -in www.crt -certfile intermediate.crt -name "www.example.com"
```

Older Windows versions may not open the AES-protected PFX files OpenSSL 3 makes by default; see [PFX and PEM](https://pkizerotohero.com/guides/convert-pfx-pem/).

### 2. Import it into the computer’s Personal store

In PowerShell **as administrator**, with [Import-PfxCertificate](https://learn.microsoft.com/en-us/powershell/module/pki/import-pfxcertificate):

```powershell
$pfxPassword = Read-Host -AsSecureString -Prompt "PFX password"
Import-PfxCertificate -FilePath C:\certs\www.pfx -CertStoreLocation Cert:\LocalMachine\My -Password $pfxPassword
```

Without `-Exportable` the key cannot be exported again, which is what you want on a web server; keep the original PFX in your secrets vault instead. In IIS Manager, the same is **server node** > **Server Certificates** > **Import**.

If you created the CSR in IIS Manager, use **Complete Certificate Request** with the CA’s `.cer` file instead. The key is already on the server.

### 3. Make sure the intermediate is in place

`Import-PfxCertificate` puts every certificate in the PFX into the store you name: “Certificates with and without private keys in the PFX file are imported”. So after step 2 the intermediate sits in the Personal store next to your certificate. Check the computer’s Intermediate Certification Authorities store:

```powershell
Get-ChildItem Cert:\LocalMachine\CA | Where-Object Subject -like '*Issuing CA*' | Format-List Subject, Thumbprint, NotAfter
```

If it is missing, import it there; never into Trusted Root:

```powershell
Import-Certificate -FilePath C:\certs\intermediate.cer -CertStoreLocation Cert:\LocalMachine\CA
```

### 4. Add the HTTPS binding

In IIS Manager: select the site, **Bindings** > **Add**. Choose type **https**, IP address **All Unassigned**, port **443**, type the **Host name**, tick **Require Server Name Indication**, and pick the certificate.

Or in PowerShell with the IISAdministration module ([New-IISSiteBinding](https://learn.microsoft.com/en-us/powershell/module/iisadministration/new-iissitebinding)):

```powershell
$cert = Get-ChildItem Cert:\LocalMachine\My |
    Where-Object { $_.HasPrivateKey -and $_.DnsNameList.Unicode -contains 'www.example.com' } |
    Sort-Object NotAfter -Descending | Select-Object -First 1

New-IISSiteBinding -Name "Default Web Site" -BindingInformation "*:443:www.example.com" `
    -CertificateThumbPrint $cert.Thumbprint -CertStoreLocation "Cert:\LocalMachine\My" `
    -Protocol https -SslFlag Sni
```

With SNI, several sites can share one IP address and port, each with its own certificate. Protocol versions and cipher suites are mostly set for the whole server in Windows (Schannel); the binding’s SSL flags, such as `DisableLegacyTLS`, adjust a few of them per site. See [How to configure TLS securely](https://pkizerotohero.com/guides/tls-configuration/).

### 5. Plan the renewal now

A renewed certificate has a new thumbprint, and the binding still points to the old one. Choose one of these:

- **Certificate Rebind** (IIS 8.5 and later): **Server Certificates** > **Enable Automatic Rebind of Renewed Certificate**. It reacts to Windows’ certificate-renewal event, so it works for renewals through Windows (manual renewal or autoenrollment), not for a new certificate you import ([Microsoft](https://learn.microsoft.com/en-us/iis/get-started/whats-new-in-iis-85/certificate-rebind-in-iis85)).
- **An ACME client** such as [win-acme](https://pkizerotohero.com/guides/win-acme-windows/), which imports the new certificate and updates the binding itself.
- **A script** that repeats steps 2 to 4, run by your deployment tooling.

## Check it worked

On the server, confirm the binding and its certificate:

```powershell
Get-IISSiteBinding -Name "Default Web Site"
netsh http show sslcert hostnameport=www.example.com:443
```

`netsh` shows the `Certificate Hash` (the thumbprint) bound to that name and port. Then test from another machine, as a client sees it:

```bash
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null | grep -E '^ [0-9] s:|^   i:|Verify return code'
```

You want two certificates, the server certificate first, and `Verify return code: 0 (ok)`. Paste the `-showcerts` output into the chain checker:

*Interactive tool: Chain checker (runs in the browser at [/tools/chain/](https://pkizerotohero.com/tools/chain/))*

## If something goes wrong

- **The certificate does not appear in the IIS list, or the binding fails.** It has no usable private key: `Get-ChildItem Cert:\LocalMachine\My | Format-Table Subject, HasPrivateKey`. Import the PFX that contains the key. If you completed a CSR made on this server, [`certutil -repairstore my <serial number>`](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certutil) can re-link the certificate to its key.
- **Browsers work, but curl, Java or apps report [`unable to verify the first certificate`](https://pkizerotohero.com/errors/openssl-verify-error-21/) or [`unable to get local issuer certificate`](https://pkizerotohero.com/errors/curl-unable-to-get-local-issuer-certificate/).** The intermediate is not being sent: repeat step 3. Windows clients may fetch it themselves, which hides the problem. See [build the full chain](https://pkizerotohero.com/guides/build-fullchain/).
- **A different site’s certificate is served.** The binding lacks SNI or a host name, or the client sends no SNI and gets the default `*:443` binding.
- **[`NET::ERR_CERT_COMMON_NAME_INVALID`](https://pkizerotohero.com/errors/chrome-err-cert-common-name-invalid/).** The certificate does not cover the host name. Check it with the [hostname matcher](https://pkizerotohero.com/tools/hostname/).
- **[`NET::ERR_CERT_DATE_INVALID`](https://pkizerotohero.com/errors/chrome-err-cert-date-invalid/) after a renewal.** The binding still points to the old certificate (step 5).
- **.NET clients say [`The remote certificate is invalid`](https://pkizerotohero.com/errors/dotnet-remote-certificate-invalid/).** One of the causes above; the error page lists how to tell them apart.

Warning

Treat the PFX like a password

The PFX holds the private key. Do not email it, do not leave copies in `C:\certs` after the import, and do not mark the key exportable unless you have a reason. Anyone with the PFX and its password can impersonate your site.

## Why this works

IIS uses Windows’ TLS stack, Schannel. When a client connects, Windows looks up the binding for the IP, port and SNI host name, loads the certificate and its private key from the computer store, and builds the [certificate chain](https://pkizerotohero.com/handbook/glossary/#certificate-chain) to send from the local stores. The key signs the [TLS handshake](https://pkizerotohero.com/handbook/glossary/#tls-handshake); the client then checks the chain against its own roots. See [Certificate chains and path validation](https://pkizerotohero.com/handbook/certificate-chains/), [The TLS 1.3 handshake](https://pkizerotohero.com/handbook/tls-handshake/) and, for renewals, [Inventory, expiry and renewal](https://pkizerotohero.com/handbook/certificate-lifecycle/).

## Go deeper

- [Import-PfxCertificate](https://learn.microsoft.com/en-us/powershell/module/pki/import-pfxcertificate): importing a PFX into the computer store.
- [New-IISSiteBinding](https://learn.microsoft.com/en-us/powershell/module/iisadministration/new-iissitebinding): HTTPS bindings, SNI and the other SSL flags.
- [Certificate Rebind in IIS 8.5](https://learn.microsoft.com/en-us/iis/get-started/whats-new-in-iis-85/certificate-rebind-in-iis85): how automatic rebinding works and when it triggers.
- [IIS 8.0 Server Name Indication](https://learn.microsoft.com/en-us/iis/get-started/whats-new-in-iis-8/iis-80-server-name-indication-sni-ssl-scalability): how SNI bindings work in IIS.

**Early edition.** Checked against the standards; an independent expert review is in progress. Found a mistake? [Tell us](https://pkizerotohero.com/contact/?topic=content-error&page=/guides/install-certificate-iis/).

Last reviewed 20 October 2026Edition 0.9

## Keep going

### Learn why it works

- [Chapter 13: Certificate chains and path validation](https://pkizerotohero.com/handbook/certificate-chains/)
- [Chapter 15: The TLS 1.3 handshake](https://pkizerotohero.com/handbook/tls-handshake/)
- [Chapter 19: Inventory, expiry and renewal](https://pkizerotohero.com/handbook/certificate-lifecycle/)

### Error pages

- [verify error:num=21:unable to verify the first certificate](https://pkizerotohero.com/errors/openssl-verify-error-21/)
- [SSL certificate problem: unable to get local issuer certificate](https://pkizerotohero.com/errors/curl-unable-to-get-local-issuer-certificate/)
- [NET::ERR\_CERT\_COMMON\_NAME\_INVALID](https://pkizerotohero.com/errors/chrome-err-cert-common-name-invalid/)
- [NET::ERR\_CERT\_DATE\_INVALID](https://pkizerotohero.com/errors/chrome-err-cert-date-invalid/)
- [The remote certificate is invalid according to the validation procedure](https://pkizerotohero.com/errors/dotnet-remote-certificate-invalid/)

### Tools

- [Chain checker](https://pkizerotohero.com/tools/chain/): Paste a chain and see which link is missing, expired or out of order.
- [Certificate decoder](https://pkizerotohero.com/tools/decoder/): Paste a PEM certificate and read every field in plain words.
- [Hostname matcher](https://pkizerotohero.com/tools/hostname/): Test whether a name matches a certificate's SANs and wildcards.

### Topics

- [TLS and HTTPS](https://pkizerotohero.com/topics/tls/)

## More guides: Install on a server

- [How to build the full chain file your server needs](https://pkizerotohero.com/guides/build-fullchain/)
- [How to install a certificate in nginx](https://pkizerotohero.com/guides/install-certificate-nginx/)
- [How to install a certificate in Apache httpd](https://pkizerotohero.com/guides/install-certificate-apache/)
- [How to install a certificate in Tomcat and other Java servers](https://pkizerotohero.com/guides/install-certificate-tomcat/)
