diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java
index f43a98cde8019f4edafc83bcb659d99604dd6732..648f231d779d6eeb48e0faf3b92a1803bc3fcb3b 100644
--- a/components/net/sf/briar/db/Database.java
+++ b/components/net/sf/briar/db/Database.java
@@ -452,6 +452,15 @@ interface Database<T> {
 	void setSubscriptions(T txn, ContactId c, Map<Group, Long> subs,
 			long timestamp) throws DbException;
 
+	/**
+	 * Records the time at which a subscription update was last sent to the
+	 * given contact.
+	 * <p>
+	 * Locking: contacts read, subscriptions write.
+	 */
+	void setSubscriptionTimestamp(T txn, ContactId c, long timestamp)
+	throws DbException;
+
 	/**
 	 * Sets the configuration for the transport with the given name, replacing
 	 * any existing configuration for that transport.
@@ -481,6 +490,15 @@ interface Database<T> {
 			Map<String, Map<String, String>> transports, long timestamp)
 	throws DbException;
 
+	/**
+	 * Records the time at which a transport update was last sent to the given
+	 * contact.
+	 * <p>
+	 * Locking: contacts read, transports write.
+	 */
+	void setTransportTimestamp(T txn, ContactId c, long timestamp)
+	throws DbException;
+
 	/**
 	 * Makes the given group visible to the given set of contacts and invisible
 	 * to any other contacts.
diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java
index 042b714f21392c90bb7af9db73c990af95e1f955..bc882aa4536e68cba5a775ca59cecdf20d3a1222 100644
--- a/components/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/components/net/sf/briar/db/DatabaseComponentImpl.java
@@ -596,26 +596,29 @@ DatabaseCleaner.Callback {
 	public void generateSubscriptionUpdate(ContactId c, SubscriptionWriter s)
 	throws DbException, IOException {
 		Map<Group, Long> subs;
+		long timestamp;
 		contactLock.readLock().lock();
 		try {
 			if(!containsContact(c)) throw new NoSuchContactException();
-			subscriptionLock.readLock().lock();
+			subscriptionLock.writeLock().lock();
 			try {
 				T txn = db.startTransaction();
 				try {
 					subs = db.getVisibleSubscriptions(txn, c);
+					timestamp = System.currentTimeMillis();
+					db.setSubscriptionTimestamp(txn, c, timestamp);
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
 					throw e;
 				}
 			} finally {
-				subscriptionLock.readLock().unlock();
+				subscriptionLock.writeLock().unlock();
 			}
 		} finally {
 			contactLock.readLock().unlock();
 		}
-		s.writeSubscriptions(subs, System.currentTimeMillis());
+		s.writeSubscriptions(subs, timestamp);
 		if(LOG.isLoggable(Level.FINE))
 			LOG.fine("Added " + subs.size() + " subscriptions to update");
 	}
@@ -623,26 +626,29 @@ DatabaseCleaner.Callback {
 	public void generateTransportUpdate(ContactId c, TransportWriter t)
 	throws DbException, IOException {
 		Map<String, Map<String, String>> transports;
+		long timestamp;
 		contactLock.readLock().lock();
 		try {
 			if(!containsContact(c)) throw new NoSuchContactException();
-			transportLock.readLock().lock();
+			transportLock.writeLock().lock();
 			try {
 				T txn = db.startTransaction();
 				try {
 					transports = db.getTransports(txn);
+					timestamp = System.currentTimeMillis();
+					db.setTransportTimestamp(txn, c, timestamp);
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
 					throw e;
 				}
 			} finally {
-				transportLock.readLock().unlock();
+				transportLock.writeLock().unlock();
 			}
 		} finally {
 			contactLock.readLock().unlock();
 		}
-		t.writeTransports(transports, System.currentTimeMillis());
+		t.writeTransports(transports, timestamp);
 		if(LOG.isLoggable(Level.FINE))
 			LOG.fine("Added " + transports.size() + " transports to update");
 	}
diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java
index 1e8d39f07eda0b8491a63cd6f50be6885a6a7346..4f9d1dbbbfd7cfb3c453b8086771cc886eefc705 100644
--- a/test/net/sf/briar/db/DatabaseComponentTest.java
+++ b/test/net/sf/briar/db/DatabaseComponentTest.java
@@ -753,6 +753,8 @@ public abstract class DatabaseComponentTest extends TestCase {
 			// Get the visible subscriptions
 			oneOf(database).getVisibleSubscriptions(txn, contactId);
 			will(returnValue(Collections.singletonMap(group, 0L)));
+			oneOf(database).setSubscriptionTimestamp(with(txn), with(contactId),
+					with(any(long.class)));
 			// Add the subscriptions to the writer
 			oneOf(subscriptionWriter).writeSubscriptions(
 					with(Collections.singletonMap(group, 0L)),
@@ -786,6 +788,8 @@ public abstract class DatabaseComponentTest extends TestCase {
 			// Get the local transport properties
 			oneOf(database).getTransports(txn);
 			will(returnValue(transports));
+			oneOf(database).setTransportTimestamp(with(txn), with(contactId),
+					with(any(long.class)));
 			// Add the properties to the writer
 			oneOf(transportWriter).writeTransports(with(transports),
 					with(any(long.class)));