diff --git a/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java b/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
index 85f383bae4372b7cfdad2e91515b4e1df94e6a1e..248602434ef9cadf46cab96105777a4630c13dad 100644
--- a/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
+++ b/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
@@ -9,6 +9,7 @@ import org.briarproject.api.db.DatabaseExecutor;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.Metadata;
 import org.briarproject.api.db.NoSuchGroupException;
+import org.briarproject.api.db.NoSuchMessageException;
 import org.briarproject.api.db.Transaction;
 import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventListener;
@@ -23,8 +24,10 @@ import org.briarproject.api.sync.MessageValidator;
 import org.briarproject.api.sync.ValidationManager;
 import org.briarproject.util.ByteUtils;
 
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Queue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
@@ -81,19 +84,48 @@ class ValidationManagerImpl implements ValidationManager, Service,
 		dbExecutor.execute(new Runnable() {
 			public void run() {
 				try {
-					// TODO: Don't do all of this in a single DB task
+					Queue<MessageId> unvalidated = new LinkedList<MessageId>();
 					Transaction txn = db.startTransaction();
 					try {
-						for (MessageId id : db.getMessagesToValidate(txn, c)) {
-							byte[] raw = db.getRawMessage(txn, id);
-							Message m = parseMessage(id, raw);
-							Group g = db.getGroup(txn, m.getGroupId());
-							validateMessage(m, g);
-						}
+						unvalidated.addAll(db.getMessagesToValidate(txn, c));
+						txn.setComplete();
+					} finally {
+						db.endTransaction(txn);
+					}
+					validateNextMessage(unvalidated);
+				} catch (DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
+	}
+
+	private void validateNextMessage(final Queue<MessageId> unvalidated) {
+		if (unvalidated.isEmpty()) return;
+		dbExecutor.execute(new Runnable() {
+			public void run() {
+				try {
+					Message m = null;
+					Group g = null;
+					Transaction txn = db.startTransaction();
+					try {
+						MessageId id = unvalidated.poll();
+						byte[] raw = db.getRawMessage(txn, id);
+						m = parseMessage(id, raw);
+						g = db.getGroup(txn, m.getGroupId());
 						txn.setComplete();
+					} catch (NoSuchMessageException e) {
+						LOG.info("Message removed before validation");
+						// Continue to next message
+					} catch (NoSuchGroupException e) {
+						LOG.info("Group removed before validation");
+						// Continue to next message
 					} finally {
 						db.endTransaction(txn);
 					}
+					if (m != null && g != null) validateMessage(m, g);
+					validateNextMessage(unvalidated);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -158,21 +190,23 @@ class ValidationManagerImpl implements ValidationManager, Service,
 		if (e instanceof MessageAddedEvent) {
 			// Validate the message if it wasn't created locally
 			MessageAddedEvent m = (MessageAddedEvent) e;
-			if (m.getContactId() != null) loadGroup(m.getMessage());
+			if (m.getContactId() != null) loadGroupAndValidate(m.getMessage());
 		}
 	}
 
-	private void loadGroup(final Message m) {
+	private void loadGroupAndValidate(final Message m) {
 		dbExecutor.execute(new Runnable() {
 			public void run() {
 				try {
+					Group g;
 					Transaction txn = db.startTransaction();
 					try {
-						validateMessage(m, db.getGroup(txn, m.getGroupId()));
+						g = db.getGroup(txn, m.getGroupId());
 						txn.setComplete();
 					} finally {
 						db.endTransaction(txn);
 					}
+					validateMessage(m, g);
 				} catch (NoSuchGroupException e) {
 					LOG.info("Group removed before validation");
 				} catch (DbException e) {