diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
index 5f27522d83073625084fe43f188c2f9193219cf8..ca7c10d7bd3292216e3bfb9812314263ec814f59 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
@@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.ProtocolException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
@@ -135,16 +136,20 @@ abstract class AbstractMailboxSession {
 		while (!terminated.get()) {
 			try {
 				MailboxRequest req = mailboxProtocol.getNextRequest();
-				if (req.getType() == END) {
-					synchronized (remoteSessionFinished) {
-						remoteSessionFinished.set(true);
-					}
+				if (req.getType() == END)
 					return;
-				}
 				ioExecutor.execute(() -> handleRequest(req));
 			} catch (InterruptedException e) {
-				logException(LOG, INFO, e);
-				return;
+				if (LOG.isLoggable(INFO))
+					LOG.info(e.toString());
+			} catch (ProtocolException e) {
+				if (LOG.isLoggable(INFO))
+					LOG.info(e.toString());
+				handleProtocolException();
+			} finally {
+				synchronized (remoteSessionFinished){
+					remoteSessionFinished.set(true);
+				}
 			}
 		}
 	}
@@ -277,6 +282,8 @@ abstract class AbstractMailboxSession {
 
 	public abstract void run() throws IOException;
 
+	protected abstract void handleProtocolException();
+
 	protected class MailboxSessionHandleException extends Exception {
 		public MailboxSessionHandleException(String error) {
 			super(error);
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxOwnerSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxOwnerSession.java
index caed520d4d85298b3803d04b87290fff1cb99f54..c794731a9eddb17bb319218b99b7102917bfb5dd 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxOwnerSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxOwnerSession.java
@@ -13,15 +13,13 @@ import java.io.IOException;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
 
-import static java.util.logging.Level.INFO;
-
 class MailboxOwnerSession extends AbstractMailboxSession {
 
 	private static final Logger LOG =
 			Logger.getLogger(MailboxOwnerSession.class.getName());
 	private final Executor ioExecutor;
 	private final MailboxProtocol mailboxProtocol;
-	private SyncSession syncSession;
+	private SyncSession duplexOutgoingSession;
 
 	public MailboxOwnerSession(ContactId contactId, Executor ioExecutor,
 			KeyManager keyManager,
@@ -42,8 +40,19 @@ class MailboxOwnerSession extends AbstractMailboxSession {
 	@Override
 	public void run() throws IOException {
 		ioExecutor.execute(() -> readRequests());
-		syncSession = createDuplexOutgoingSession();
-		syncSession.run();
+		duplexOutgoingSession = createDuplexOutgoingSession();
+		duplexOutgoingSession.run();
+		try {
+			endSession();
+		} catch (InterruptedException e) {
+			throw new IOException("Interrupted while ending session");
+		}
+	}
+
+	@Override
+	protected void handleProtocolException() {
+		if (duplexOutgoingSession != null)
+			duplexOutgoingSession.interrupt();
 	}
 
 	@Override
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java
index cef10a8b62ee6a87417878ab5009b9cc1c9936d7..9085b834b89af45e0990361f98c821173d97dc0a 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java
@@ -25,6 +25,7 @@ class PrivateMailboxSession extends AbstractMailboxSession {
 	private static final Logger LOG =
 			Logger.getLogger(PrivateMailboxSession.class.getName());
 	private MailboxProtocol mailboxProtocol;
+	private SyncSession duplexOutgoingSession;
 
 	public PrivateMailboxSession(ContactId contactId, Executor ioExecutor,
 			KeyManager keyManager,
@@ -71,7 +72,8 @@ class PrivateMailboxSession extends AbstractMailboxSession {
 	@Override
 	public void run() throws IOException {
 		ioExecutor.execute(() -> super.readRequests());
-		createDuplexOutgoingSession().run();
+		duplexOutgoingSession = createDuplexOutgoingSession();
+		duplexOutgoingSession.run();
 		try {
 			endSession();
 		} catch (InterruptedException e) {
@@ -79,6 +81,12 @@ class PrivateMailboxSession extends AbstractMailboxSession {
 		}
 	}
 
+	@Override
+	protected void handleProtocolException() {
+		if (duplexOutgoingSession != null)
+			duplexOutgoingSession.interrupt();
+	}
+
 	@Override
 	public void handleStore(MailboxRequestStore req)
 			throws MailboxSessionHandleException {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java
index 7df043a439d28f4ed5273c8b829b5aab4ca928d9..e5db5b2f1e94b0a479772591a59df7cbe8885945 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java
@@ -53,6 +53,8 @@ public class MailboxProtocol implements Runnable {
 
 	public void sendKeepAlive() throws IOException {
 		// flush the writer without pending data to send a keepalive
+		if (stopped.get())
+			throw new ProtocolException("Mailbox protocol has stopped");
 		synchronized (mailboxBdfWriter) {
 			mailboxBdfWriter.flush();
 		}
@@ -93,8 +95,12 @@ public class MailboxProtocol implements Runnable {
 	}
 
 	public MailboxRequest getNextRequest()
-			throws InterruptedException {
-		return inQueue.take();
+			throws InterruptedException, ProtocolException {
+		MailboxRequest req =  inQueue.take();
+		if (stopped.get())
+			throw new ProtocolException("Protocol has stopped");
+
+		return req;
 	}
 
 	@Override
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocolIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocolIntegrationTest.java
index 7a5420289f917dc25da8d6467a5d1182e156adfb..d1e02bbbb2c846a391431f5355ee847855ac6da7 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocolIntegrationTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocolIntegrationTest.java
@@ -13,6 +13,7 @@ import org.junit.Test;
 import java.io.IOException;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
+import java.net.ProtocolException;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Executor;
 import java.util.concurrent.RejectedExecutionHandler;
@@ -73,7 +74,7 @@ public class MailboxProtocolIntegrationTest extends BrambleTestCase {
 		mailboxProtocol = new MailboxProtocol(ioExecutor, bdfWriter, bdfReader);
 	}
 
-	@Test
+	@Test(expected = ProtocolException.class)
 	public void testProtocolTerminationOnClosedConnection()
 			throws IOException, InterruptedException {
 		ioExecutor.execute(mailboxProtocol);
@@ -88,12 +89,13 @@ public class MailboxProtocolIntegrationTest extends BrambleTestCase {
 		pipedOS.close();
 
 		// And "End" request should be the next read request
-		MailboxRequest recvReq = mailboxProtocol.getNextRequest();
-		assertEquals(END, recvReq.getType());
-
-		// pending request should be marked as failed
-		assertEquals(false, req.awaitAndGetResponse());
-		assertEquals("Connection closed", req.getError());
+		try {
+			MailboxRequest recvReq = mailboxProtocol.getNextRequest();
+		}finally {
+			// pending request should be marked as failed
+			assertEquals(false, req.awaitAndGetResponse());
+			assertEquals("Connection closed", req.getError());
+		}
 	}