diff --git a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
index 0f45d47cf1ddadcebd995e2b2b2d6cccacf35b09..dd0e9450a0f5dafeb9642ac39118970385a34841 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
@@ -199,6 +199,10 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa
         if (_log.shouldLog(Log.DEBUG))
             _log.debug(prefix() + "verification successful for " + _con);
 
+        // Adjust skew calculation now that we know RTT
+        // rtt from receiving #1 to receiving #3
+        long rtt = _context.clock().now() - _con.getCreated();
+        _peerSkew -= ((rtt / 2) + 500) / 1000;
         long diff = 1000*Math.abs(_peerSkew);
         if (!_context.clock().getUpdatedSuccessfully()) {
             // Adjust the clock one time in desperation
@@ -209,16 +213,12 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa
             if (diff != 0)
                 _log.logAlways(Log.WARN, "NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff));
         } else if (diff >= Router.CLOCK_FUDGE_FACTOR) {
-            _context.statManager().addRateData("ntcp.invalidInboundSkew", diff);
-            _transport.markReachable(aliceHash, true);
             // Only banlist if we know what time it is
             _context.banlist().banlistRouter(DataHelper.formatDuration(diff),
                                              aliceHash,
                                                _x("Excessive clock skew: {0}"));
             _transport.setLastBadSkew(_peerSkew);
-            if (getVersion() < 2)
-                fail("Clocks too skewed (" + diff + " ms)", null, true);
-            else if (_log.shouldWarn())
+            if (_log.shouldWarn())
                 _log.warn("Clocks too skewed (" + diff + " ms)");
             _msg3p2FailReason = NTCPConnection.REASON_SKEW;
             return false;
@@ -361,18 +361,21 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa
             _msg3p2len = (int) DataHelper.fromLong(options, 4, 2);
             long tsA = DataHelper.fromLong(options, 8, 4);
             long now = _context.clock().now();
-            // In NTCP1, timestamp comes in msg 3 so we know the RTT.
-            // In NTCP2, it comes in msg 1, so just guess.
-            // We could defer this to msg 3 to calculate the RTT?
-            long rtt = 250;
-            _peerSkew = (now - (tsA * 1000) - (rtt / 2) + 500) / 1000; 
-            if ((_peerSkew > MAX_SKEW || _peerSkew < 0 - MAX_SKEW) &&
-                !_context.clock().getUpdatedSuccessfully()) {
-                // If not updated successfully, allow it.
-                // This isn't very likely, outbound will do it first
-                // See verifyInbound() above.
-                fail("Clock Skew: " + _peerSkew, null, true);
-                return;
+            // Will be adjusted for RTT in verifyInbound()
+            _peerSkew = (now - (tsA * 1000) + 500) / 1000; 
+            if (_peerSkew > MAX_SKEW || _peerSkew < 0 - MAX_SKEW) {
+                long diff = 1000*Math.abs(_peerSkew);
+                _context.statManager().addRateData("ntcp.invalidInboundSkew", diff);
+                _transport.setLastBadSkew(_peerSkew);
+                if (_log.shouldWarn())
+                    _log.warn("Clock Skew: " + _peerSkew + " on " + this);
+                // Do them a favor, keep going with msg 2 so they get our timestamp.
+                // They should disconnect after that.
+                // If they do send a msg 3, verifyInbound() will catch it and
+                // will send a destroy with code 7 and
+                // ban the peer for a while.
+                //fail("Clock Skew: " + _peerSkew, null, true);
+                //return;
             }
             if (_msg3p2len < MSG3P2_MIN || _msg3p2len > MSG3P2_MAX) {
                 fail("bad msg3p2 len: " + _msg3p2len);
@@ -671,9 +674,10 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa
             ok = verifyInboundNetworkID(ri);
             if (!ok)
                 throw new DataFormatException("NTCP2 network ID mismatch");
-            // hash collision?
-            // expired RI?
-            _msg3p2FailReason = NTCPConnection.REASON_MSG3;
+            // generally expired/future RI
+            // don't change reason if already set as clock skew
+            if (_msg3p2FailReason <= 0)
+                _msg3p2FailReason = NTCPConnection.REASON_MSG3;
             throw new DataFormatException("RI store fail: " + ri, iae);
         }
         _con.setRemotePeer(_aliceIdent);
diff --git a/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java b/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
index 4e53146c1169a006c3997709069593e1d1a76a53..c576fa2a328f6afc4e656d26f5247ae24b89df35 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
@@ -300,8 +300,23 @@ class OutboundNTCP2State implements EstablishState {
             long rtt = now - _con.getCreated();
             _peerSkew = (now - (tsB * 1000) - (rtt / 2) + 500) / 1000; 
             if (_peerSkew > MAX_SKEW || _peerSkew < 0 - MAX_SKEW) {
-                fail("Clock Skew: " + _peerSkew, null, true);
-                return;
+                long diff = 1000 * Math.abs(_peerSkew);
+                if (_context.clock().getUpdatedSuccessfully()) {
+                    // usual case
+                    _context.statManager().addRateData("ntcp.invalidOutboundSkew", diff);
+                    fail("Clock Skew: " + _peerSkew, null, true);
+                    // Only banlist if we know what time it is
+                    _context.banlist().banlistRouter(DataHelper.formatDuration(diff),
+                                                     _con.getRemotePeer().calculateHash(),
+                                                     "Excessive clock skew: {0}");  // _x in IES
+                    _transport.setLastBadSkew(_peerSkew);
+                    return;
+                }
+                // Adjust the clock one time in desperation
+                // We are Alice, he is Bob, adjust to match Bob
+                _context.clock().setOffset(1000 * (0 - _peerSkew), true);
+                _peerSkew = 0;
+                _log.logAlways(Log.WARN, "NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff));
             }
             changeState(State.OB_GOT_HXY);
             _received = 0;