diff --git a/router/java/src/net/i2p/router/TunnelInfo.java b/router/java/src/net/i2p/router/TunnelInfo.java
index a3b89219382000a7a617b9b7d274b15e91276278..0f038e5d2df25cd6922f3387a813312488154458 100644
--- a/router/java/src/net/i2p/router/TunnelInfo.java
+++ b/router/java/src/net/i2p/router/TunnelInfo.java
@@ -55,6 +55,7 @@ public class TunnelInfo extends DataStructureImpl {
     private boolean _ready;
     private boolean _wasEverReady;
     private int _messagesProcessed;
+    private int _tunnelFailures;
     
     public TunnelInfo(I2PAppContext context) {
         _context = context;
@@ -77,6 +78,7 @@ public class TunnelInfo extends DataStructureImpl {
         _created = _context.clock().now();
         _lastTested = -1;
         _messagesProcessed = 0;
+        _tunnelFailures = 0;
     }
     
     public TunnelId getTunnelId() { return _id; }
@@ -182,6 +184,13 @@ public class TunnelInfo extends DataStructureImpl {
     /** we have just processed a message for this tunnel */
     public void messageProcessed() { _messagesProcessed++; }
     
+    /** 
+     * the tunnel was (potentially) unable to pass a message through.
+     * 
+     * @return the new number of tunnel failures ever for this tunnel
+     */
+    public int incrementFailures() { return ++_tunnelFailures; }
+    
     public void readBytes(InputStream in) throws DataFormatException, IOException {
         _options = DataHelper.readProperties(in);
         Boolean includeDest = DataHelper.readBoolean(in);
diff --git a/router/java/src/net/i2p/router/tunnelmanager/ClientTunnelPool.java b/router/java/src/net/i2p/router/tunnelmanager/ClientTunnelPool.java
index e03a1dc64dcd7cd346aa3d2abc552506aec0524e..784b19db6e3979c2e5e9df18df4f0ad64f6eecb4 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/ClientTunnelPool.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/ClientTunnelPool.java
@@ -131,7 +131,7 @@ class ClientTunnelPool {
      *
      */
     public int getSafePoolSize() {
-        return getSafePoolSize(0);
+        return getSafePoolSize(2*60*1000);
     }
     /**
      * Get the safe # pools at some point in the future
@@ -140,7 +140,7 @@ class ClientTunnelPool {
      */
     public int getSafePoolSize(long futureMs) {
         int numSafe = 0;
-        long expireAfter = _context.clock().now() + Router.CLOCK_FUDGE_FACTOR + futureMs;
+        long expireAfter = _context.clock().now() + futureMs;
         for (Iterator iter = getInboundTunnelIds().iterator(); iter.hasNext(); ) {
             TunnelId id = (TunnelId)iter.next();
             TunnelInfo info = getInboundTunnel(id);
diff --git a/router/java/src/net/i2p/router/tunnelmanager/ClientTunnelPoolManagerJob.java b/router/java/src/net/i2p/router/tunnelmanager/ClientTunnelPoolManagerJob.java
index a2fe863746ef98b78fcfc9b16fa8ce0f7bc1806c..965ca4348fd8292ab3fbbaeafd8bde2caae04207 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/ClientTunnelPoolManagerJob.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/ClientTunnelPoolManagerJob.java
@@ -50,7 +50,7 @@ class ClientTunnelPoolManagerJob extends JobImpl {
                 return;
             }
             int requestedPoolSize = _clientPool.getClientSettings().getNumInboundTunnels();
-            int safePoolSize = _clientPool.getSafePoolSize(POOL_CHECK_DELAY);
+            int safePoolSize = _clientPool.getSafePoolSize(2*60*1000 + POOL_CHECK_DELAY);
             if (safePoolSize < requestedPoolSize) {
                 requestMoreTunnels(requestedPoolSize-safePoolSize);
             }
diff --git a/router/java/src/net/i2p/router/tunnelmanager/RequestTunnelJob.java b/router/java/src/net/i2p/router/tunnelmanager/RequestTunnelJob.java
index 85e3dc0cc06b2708dd5235a7be064a137efb9fd4..f87215c2806b1994394639277fe004027b440eed 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/RequestTunnelJob.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/RequestTunnelJob.java
@@ -260,8 +260,8 @@ public class RequestTunnelJob extends JobImpl {
                     _log.info("Sending tunnel create to " + _target.getIdentity().getHash().toBase64() +
                     " to inbound gateway " + _inboundGateway.getGateway().toBase64() +
                     " : " + _inboundGateway.getTunnelId().getTunnelId());
-                ReplyJob onReply = new Success(_participant, _wrappedKey, _wrappedTags, _wrappedTo);
-                Job onFail = new Failure(_participant);
+                ReplyJob onReply = new Success(_participant, _wrappedKey, _wrappedTags, _wrappedTo, _inboundGateway.getTunnelId(), _outboundTunnel);
+                Job onFail = new Failure(_participant, _inboundGateway.getTunnelId(), _outboundTunnel);
                 MessageSelector selector = new Selector(_participant);
                 SendTunnelMessageJob j = new SendTunnelMessageJob(getContext(), _garlicMessage, 
                                                                   _outboundTunnel, _target.getIdentity().getHash(), 
@@ -550,9 +550,11 @@ public class RequestTunnelJob extends JobImpl {
         private SessionKey _wrappedKey;
         private Set _wrappedTags;
         private PublicKey _wrappedTo;
+        private TunnelId _replyTunnelId;
+        private TunnelId _outboundTunnelId;
         private long _started;
         
-        public Success(TunnelInfo tunnel, SessionKey wrappedKey, Set wrappedTags, PublicKey wrappedTo) {
+        public Success(TunnelInfo tunnel, SessionKey wrappedKey, Set wrappedTags, PublicKey wrappedTo, TunnelId replyTunnelId, TunnelId outboundTunnelId) {
             super(RequestTunnelJob.this.getContext());
             _tunnel = tunnel;
             _messages = new LinkedList();
@@ -560,6 +562,8 @@ public class RequestTunnelJob extends JobImpl {
             _wrappedKey = wrappedKey;
             _wrappedTags = wrappedTags;
             _wrappedTo = wrappedTo;
+            _replyTunnelId = replyTunnelId;
+            _outboundTunnelId = outboundTunnelId;
             _started = getContext().clock().now();
         }
         
@@ -644,10 +648,14 @@ public class RequestTunnelJob extends JobImpl {
     
     private class Failure extends JobImpl {
         private TunnelInfo _tunnel;
+        private TunnelId _outboundTunnelId;
+        private TunnelId _replyTunnelId;
         private long _started;
-        public Failure(TunnelInfo tunnel) {
+        public Failure(TunnelInfo tunnel, TunnelId replyTunnelId, TunnelId outboundTunnelId) {
             super(RequestTunnelJob.this.getContext());
             _tunnel = tunnel;
+            _replyTunnelId = replyTunnelId;
+            _outboundTunnelId = outboundTunnelId;
             _started = getContext().clock().now();
         }
         
@@ -669,6 +677,11 @@ public class RequestTunnelJob extends JobImpl {
             // perhaps not an explicit reject, but an implicit one (due to dropped messages, tunnel failure, etc)
             getContext().profileManager().tunnelRejected(_tunnel.getThisHop(), responseTime, false);
             getContext().profileManager().messageFailed(_tunnel.getThisHop());
+            
+            // one (or both) of the tunnels used to send the request / receive a reply failed
+            _pool.tunnelFailed(_replyTunnelId);
+            _pool.tunnelFailed(_outboundTunnelId);
+            
             Failure.this.getContext().statManager().updateFrequency("tunnel.buildFailFrequency");
             fail();
         }
diff --git a/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java b/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java
index 53149209c4e67299931a72a04cc51d09e8020ba0..50a8adbb0efbf425db68b2515ce0bc4b90008cb5 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java
@@ -524,13 +524,22 @@ class TunnelPool {
         return found;
     }
     
+    private static final int MAX_FAILURES_PER_TUNNEL = 2;
+    
     public void tunnelFailed(TunnelId id) {
         if (!_isLive) return;
-        if (_log.shouldLog(Log.WARN)) 
-            _log.warn("Tunnel " + id + " marked as not ready, since it /failed/", new Exception("Failed tunnel"));
         TunnelInfo info = getTunnelInfo(id);
         if (info == null)
             return;
+        int failures = info.incrementFailures();
+        if (failures <= MAX_FAILURES_PER_TUNNEL) {
+            if (_log.shouldLog(Log.INFO))
+                _log.info("Tunnel " + id + " failure " + failures + ", but not fatal yet");
+            return;
+        }
+        
+        if (_log.shouldLog(Log.WARN)) 
+            _log.warn("Tunnel " + id + " marked as not ready, since it /failed/", new Exception("Failed tunnel"));
         _context.messageHistory().tunnelFailed(info.getTunnelId());
         info.setIsReady(false);
         Hash us = _context.routerHash();