# NSURLErrorDomain -1200: "An SSL error has occurred" on iOS

> NSURLErrorDomain Code=-1200 means an iOS or macOS app's TLS handshake failed, often due to App Transport Security rules. How to diagnose and fix it.

Source: https://ssl.sh/errors/nsurlerrordomain-1200/
Last updated: 2026-11-10

**NSURLErrorDomain Code=-1200 means an app on iOS or macOS could not establish a secure connection: the TLS handshake failed.** Apple's URL loading system enforces App Transport Security (ATS), so servers that are fine for some browsers can still fail inside apps. The fix is almost always on the server, occasionally in the app's ATS settings.

## Is it the site or your device?

Almost always the server: it fails App Transport Security requirements. Check the API or website host with the [SSL checker](https://ssl.sh/tools/ssl-checker/):

```bash
curl ssl.sh/example.com
```

If the server lacks TLS 1.2, uses weak ciphers or has an incomplete chain, it fails for every user. If the server passes and only some users fail, look at their networks and installed profiles. On a Mac, run Apple's ATS diagnostics against the exact URL the app uses:

```bash
nscurl --ats-diagnostics --verbose https://api.example.com
```

## Causes

### 1. Server does not meet ATS requirements

ATS needs TLS 1.2 or newer and forward-secret (ECDHE) cipher suites. Servers offering only TLS 1.0/1.1 or RSA key exchange fail with -1200.

### 2. Certificate does not meet Apple's rules

SHA-1 signatures, RSA keys under 2048 bits, missing SAN entries or excessive validity periods break ATS or Apple's trust evaluation. Depending on where it fails, you see -1200 or -1202.

### 3. Incomplete chain or private CA

A missing intermediate or a private CA without the root installed usually produces -1202, but some handshake paths report -1200. Fix the chain with the [chain builder](https://ssl.sh/tools/chain-builder/).

### 4. Network interception

Company proxies, captive Wi-Fi portals and VPN/filter profiles can break TLS. Test on mobile data.

### 5. Certificate pinning mismatch

If the app pins a certificate or public key and the server rotated its certificate, the app's own pinning code rejects the connection, often surfacing as -1200 or a cancelled request (-999).

## What it looks like on each device

| Context | What you see |
|---|---|
| iOS / macOS app logs | `NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."` |
| Same server in Safari | ["Safari can't establish a secure connection"](https://ssl.sh/errors/safari-cant-establish-secure-connection/) |
| Untrusted certificate in an app | `NSURLErrorDomain Code=-1202` |
| Android apps | [Trust anchor for certification path not found](https://ssl.sh/errors/android-trust-anchor-not-found/) or `SSLHandshakeException` |

## How site owners fix it

A server with TLS 1.2 or newer, ECDHE ciphers and a compliant public certificate fixes it without app changes.

**1. Bring the server up to ATS standards.**

```nginx
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_certificate /etc/nginx/ssl/api.example.com.fullchain.pem;
```

**2. Use a public certificate with a full chain.** Check with `curl ssl.sh/example.com`.

**3. If you cannot change the server,** add a narrow exception in the app's Info.plist for that domain only:

```xml
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>legacy.example.com</key>
    <dict>
      <key>NSExceptionRequiresForwardSecrecy</key>
      <false/>
    </dict>
  </dict>
</dict>
```

**4. Plan pin rotations** by pinning to more than one key, and update the app before the server certificate changes.
