diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php
index 2690be79264e11357c72f3000d804595864dfd19..5373158c214e1ee220b72dfd2a4164944a3be574 100644
--- a/lib/SimpleSAML/Session.php
+++ b/lib/SimpleSAML/Session.php
@@ -160,10 +160,11 @@ class SimpleSAML_Session
             if ($this->sessionId === null) {
                 $this->sessionId = $sh->newSessionId();
             }
-
         } else { // regular session
             $sh = SimpleSAML_SessionHandler::getSessionHandler();
             $this->sessionId = $sh->newSessionId();
+            $sh->setCookie($sh->getSessionCookieName(), $this->sessionId, $sh->getCookieParams());
+
 
             $this->trackid = bin2hex(openssl_random_pseudo_bytes(5));
             SimpleSAML\Logger::setTrackId($this->trackid);
@@ -197,19 +198,15 @@ class SimpleSAML_Session
         $session = null;
         try {
             $session = self::getSession();
-
         } catch (Exception $e) {
-            // for some reason, we were unable to initialize this session, use a transient session instead
-            self::useTransientSession();
-
+            /*
+             * For some reason, we were unable to initialize this session. Note that this error might be temporary, and
+             * it's possible that we can recover from it in subsequent requests, so we should not try to create a new
+             * session here. Therefore, use just a transient session and throw the exception for someone else to handle
+             * it.
+             */
             SimpleSAML\Logger::error('Error loading session: '.$e->getMessage());
-            if ($e instanceof SimpleSAML_Error_Exception) {
-                $cause = $e->getCause();
-                if ($cause instanceof Exception) {
-                    throw $cause;
-                }
-            }
-            throw $e;
+            self::useTransientSession($e);
         }
 
         // if getSession() found it, use it
@@ -227,8 +224,17 @@ class SimpleSAML_Session
             return self::$instance;
         }
 
-        // create a new session
-        return self::load(new SimpleSAML_Session());
+        // try to create a new session
+        try {
+            self::load(new SimpleSAML_Session());
+        } catch (\SimpleSAML\Error\CannotSetCookie $e) {
+            // can't create a regular session because we can't set cookies. Use transient.
+            SimpleSAML\Logger::error('Error creating session: '.$e->getMessage());
+            self::useTransientSession();
+        }
+
+        // we must have a session now, either regular or transient
+        return self::$instance;
     }
 
     /**
diff --git a/lib/SimpleSAML/SessionHandler.php b/lib/SimpleSAML/SessionHandler.php
index 23d826f53986d2b12310486c1b0fecbdead844bf..cfd8307605accaf6146bdb146f6f8a4ffeaa2627 100644
--- a/lib/SimpleSAML/SessionHandler.php
+++ b/lib/SimpleSAML/SessionHandler.php
@@ -54,7 +54,7 @@ abstract class SimpleSAML_SessionHandler
 
 
     /**
-     * Create and set new session id.
+     * Create a new session id.
      *
      * @return string The new session id.
      */
@@ -95,6 +95,18 @@ abstract class SimpleSAML_SessionHandler
     abstract public function loadSession($sessionId = null);
 
 
+    /**
+     * Set a session cookie.
+     *
+     * @param string $sessionName The name of the session.
+     * @param string|null $sessionID The session ID to use. Set to null to delete the cookie.
+     * @param array|null $cookieParams Additional parameters to use for the session cookie.
+     *
+     * @throws \SimpleSAML\Error\CannotSetCookie If we can't set the cookie.
+     */
+    abstract public function setCookie($sessionName, $sessionID, array $cookieParams = null);
+
+
     /**
      * Initialize the session handler.
      *
@@ -125,7 +137,6 @@ abstract class SimpleSAML_SessionHandler
      */
     public function hasSessionCookie()
     {
-
         return true;
     }
 
@@ -138,7 +149,6 @@ abstract class SimpleSAML_SessionHandler
      */
     public function getCookieParams()
     {
-
         $config = SimpleSAML_Configuration::getInstance();
 
         return array(
@@ -149,26 +159,4 @@ abstract class SimpleSAML_SessionHandler
             'httponly' => true,
         );
     }
-
-
-    /**
-     * Set a session cookie.
-     *
-     * @param string      $name The name of the session cookie.
-     * @param string|null $value The value of the cookie. Set to null to delete the cookie.
-     * @param array|null  $params Additional params to use for the session cookie.
-     */
-    public function setCookie($name, $value, array $params = null)
-    {
-        assert('is_string($name)');
-        assert('is_string($value) || is_null($value)');
-
-        if ($params !== null) {
-            $params = array_merge($this->getCookieParams(), $params);
-        } else {
-            $params = $this->getCookieParams();
-        }
-
-        \SimpleSAML\Utils\HTTP::setCookie($name, $value, $params);
-    }
 }
diff --git a/lib/SimpleSAML/SessionHandlerCookie.php b/lib/SimpleSAML/SessionHandlerCookie.php
index c8409a8d70a22c21bcd9d1cd02c77f931e5a267c..e5c02bff6b9b671cedc800342da26f3fde2c0903 100644
--- a/lib/SimpleSAML/SessionHandlerCookie.php
+++ b/lib/SimpleSAML/SessionHandlerCookie.php
@@ -45,7 +45,7 @@ abstract class SimpleSAML_SessionHandlerCookie extends SimpleSAML_SessionHandler
 
 
     /**
-     * Create and set new session id.
+     * Create a new session id.
      *
      * @return string The new session id.
      */
@@ -53,7 +53,6 @@ abstract class SimpleSAML_SessionHandlerCookie extends SimpleSAML_SessionHandler
     {
         $this->session_id = self::createSessionID();
         SimpleSAML_Session::createSession($this->session_id);
-        $this->setCookie($this->cookie_name, $this->session_id);
 
         return $this->session_id;
     }
@@ -142,4 +141,28 @@ abstract class SimpleSAML_SessionHandlerCookie extends SimpleSAML_SessionHandler
     {
         return array_key_exists($this->cookie_name, $_COOKIE);
     }
+
+
+    /**
+     * Set a session cookie.
+     *
+     * @param string $sessionName The name of the session.
+     * @param string|null $sessionID The session ID to use. Set to null to delete the cookie.
+     * @param array|null $cookieParams Additional parameters to use for the session cookie.
+     *
+     * @throws \SimpleSAML\Error\CannotSetCookie If we can't set the cookie.
+     */
+    public function setCookie($sessionName, $sessionID, array $cookieParams = null)
+    {
+        assert('is_string($sessionName)');
+        assert('is_string($sessionID) || is_null($sessionID)');
+
+        if ($cookieParams !== null) {
+            $params = array_merge($this->getCookieParams(), $cookieParams);
+        } else {
+            $params = $this->getCookieParams();
+        }
+
+        \SimpleSAML\Utils\HTTP::setCookie($sessionName, $sessionID, $params, true);
+    }
 }
diff --git a/lib/SimpleSAML/SessionHandlerPHP.php b/lib/SimpleSAML/SessionHandlerPHP.php
index 6f952b39e56a993d40ebfd67d4bb8bf775df4788..8f6ee835f7c3edd697edc38af0b9dd21d5a8f135 100644
--- a/lib/SimpleSAML/SessionHandlerPHP.php
+++ b/lib/SimpleSAML/SessionHandlerPHP.php
@@ -147,38 +147,17 @@ class SimpleSAML_SessionHandlerPHP extends SimpleSAML_SessionHandler
 
 
     /**
-     * Create and set new session id.
+     * Create a new session id.
      *
      * @return string The new session id.
-     *
-     * @throws SimpleSAML_Error_Exception If the cookie is marked as secure but we are not using HTTPS, or the headers
-     * were already sent and therefore we cannot set the cookie.
      */
     public function newSessionId()
     {
-        $session_cookie_params = session_get_cookie_params();
-
-        if ($session_cookie_params['secure'] && !\SimpleSAML\Utils\HTTP::isHTTPS()) {
-            throw new SimpleSAML_Error_Exception('Session start with secure cookie not allowed on http.');
-        }
-
-        if (headers_sent()) {
-            throw new SimpleSAML_Error_Exception('Cannot create new session - headers already sent.');
-        }
-
         // generate new (secure) session id
         $sessionId = bin2hex(openssl_random_pseudo_bytes(16));
         SimpleSAML_Session::createSession($sessionId);
 
-        if (session_id() !== '') {
-            // session already started, close it
-            session_write_close();
-        }
-
-        session_id($sessionId);
-        $this->sessionStart();
-
-        return session_id();
+        return $sessionId;
     }
 
 
@@ -321,4 +300,45 @@ class SimpleSAML_SessionHandlerPHP extends SimpleSAML_SessionHandler
 
         return $ret;
     }
+
+
+    /**
+     * Set a session cookie.
+     *
+     * @param string $sessionName The name of the session.
+     * @param string|null $sessionID The session ID to use. Set to null to delete the cookie.
+     * @param array|null $cookieParams Additional parameters to use for the session cookie.
+     *
+     * @throws \SimpleSAML\Error\CannotSetCookie If we can't set the cookie.
+     */
+    public function setCookie($sessionName, $sessionID, array $cookieParams = null)
+    {
+        if ($cookieParams === null) {
+            $cookieParams = session_get_cookie_params();
+        }
+
+        if ($cookieParams['secure'] && !\SimpleSAML\Utils\HTTP::isHTTPS()) {
+            throw new SimpleSAML\Error\CannotSetCookie('Secure cookies not allowed on http.');
+        }
+
+        if (headers_sent()) {
+            throw new SimpleSAML\Error\CannotSetCookie('Headers already sent.');
+        }
+
+        session_set_cookie_params(
+            $cookieParams['lifetime'],
+            $cookieParams['path'],
+            $cookieParams['domain'],
+            $cookieParams['secure'],
+            $cookieParams['httponly']
+        );
+
+        if (session_id() !== '') {
+            // session already started, close it
+            session_write_close();
+        }
+
+        session_id($sessionID);
+        $this->sessionStart();
+    }
 }