diff --git a/CHANGES.md b/CHANGES.md
index a3d5969a5c03..d26ff808c711 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,11 @@
 Change Log
 ==========
 
+### 1.66.0 - 2020-02-03
+
+##### Fixes :wrench:
+* Fixed a bug where the camera could go underground during mouse navigation. [#8504](https://github.com/AnalyticalGraphicsInc/cesium/pull/8504)
+
 ### 1.65.0 - 2020-01-06
 
 ##### Fixes :wrench:
diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js
index 4ce27eb78ef0..071d3c509aef 100644
--- a/Source/Scene/Camera.js
+++ b/Source/Scene/Camera.js
@@ -215,7 +215,6 @@ import SceneMode from './SceneMode.js';
         this._projection = projection;
         this._maxCoord = projection.project(new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO));
         this._max2Dfrustum = undefined;
-        this._suspendTerrainAdjustment = false;
 
         // set default view
         rectangleCameraPosition3D(this, Camera.DEFAULT_VIEW_RECTANGLE, this.position, true);
@@ -380,76 +379,6 @@ import SceneMode from './SceneMode.js';
         }
     };
 
-    var scratchAdjustHeightTransform = new Matrix4();
-    var scratchAdjustHeightCartographic = new Cartographic();
-
-    Camera.prototype._adjustHeightForTerrain = function() {
-        var scene = this._scene;
-
-        var screenSpaceCameraController = scene.screenSpaceCameraController;
-        var enableCollisionDetection = screenSpaceCameraController.enableCollisionDetection;
-        var minimumCollisionTerrainHeight = screenSpaceCameraController.minimumCollisionTerrainHeight;
-        var minimumZoomDistance = screenSpaceCameraController.minimumZoomDistance;
-
-        if (this._suspendTerrainAdjustment || !enableCollisionDetection) {
-            return;
-        }
-
-        var mode = this._mode;
-        var globe = scene.globe;
-
-        if (!defined(globe) || mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
-            return;
-        }
-
-        var ellipsoid = globe.ellipsoid;
-        var projection = scene.mapProjection;
-
-        var transform;
-        var mag;
-        if (!Matrix4.equals(this.transform, Matrix4.IDENTITY)) {
-            transform = Matrix4.clone(this.transform, scratchAdjustHeightTransform);
-            mag = Cartesian3.magnitude(this.position);
-            this._setTransform(Matrix4.IDENTITY);
-        }
-
-        var cartographic = scratchAdjustHeightCartographic;
-        if (mode === SceneMode.SCENE3D) {
-            ellipsoid.cartesianToCartographic(this.position, cartographic);
-        } else {
-            projection.unproject(this.position, cartographic);
-        }
-
-        var heightUpdated = false;
-        if (cartographic.height < minimumCollisionTerrainHeight) {
-            var height = globe.getHeight(cartographic);
-            if (defined(height)) {
-                height += minimumZoomDistance;
-                if (cartographic.height < height) {
-                    cartographic.height = height;
-                    if (mode === SceneMode.SCENE3D) {
-                        ellipsoid.cartographicToCartesian(cartographic, this.position);
-                    } else {
-                        projection.project(cartographic, this.position);
-                    }
-                    heightUpdated = true;
-                }
-            }
-        }
-
-        if (defined(transform)) {
-            this._setTransform(transform);
-            if (heightUpdated) {
-                Cartesian3.normalize(this.position, this.position);
-                Cartesian3.negate(this.position, this.direction);
-                Cartesian3.multiplyByScalar(this.position, Math.max(mag, minimumZoomDistance), this.position);
-                Cartesian3.normalize(this.direction, this.direction);
-                Cartesian3.cross(this.direction, this.up, this.right);
-                Cartesian3.cross(this.right, this.direction, this.up);
-            }
-        }
-    };
-
     function convertTransformForColumbusView(camera) {
         Transforms.basisTo2D(camera._projection, camera._transform, camera._actualTransform);
     }
@@ -976,16 +905,6 @@ import SceneMode from './SceneMode.js';
         if (this._mode === SceneMode.SCENE2D) {
             clampMove2D(this, this.position);
         }
-
-        var globe = this._scene.globe;
-        var globeFinishedUpdating = !defined(globe) || (globe._surface.tileProvider.ready && globe._surface._tileLoadQueueHigh.length === 0 && globe._surface._tileLoadQueueMedium.length === 0 && globe._surface._tileLoadQueueLow.length === 0 && globe._surface._debug.tilesWaitingForChildren === 0);
-        if (this._suspendTerrainAdjustment) {
-            this._suspendTerrainAdjustment = !globeFinishedUpdating;
-        }
-
-        if (globeFinishedUpdating) {
-            this._adjustHeightForTerrain();
-        }
     };
 
     var setTransformPosition = new Cartesian3();
@@ -1275,8 +1194,6 @@ import SceneMode from './SceneMode.js';
         scratchHpr.pitch = defaultValue(orientation.pitch, -CesiumMath.PI_OVER_TWO);
         scratchHpr.roll = defaultValue(orientation.roll, 0.0);
 
-        this._suspendTerrainAdjustment = true;
-
         if (mode === SceneMode.SCENE3D) {
             setView3D(this, destination, scratchHpr);
         } else if (mode === SceneMode.SCENE2D) {
diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js
index eb17e1ac979c..30cff1b60dd3 100644
--- a/Source/Scene/Globe.js
+++ b/Source/Scene/Globe.js
@@ -618,19 +618,26 @@ import TileSelectionResult from './TileSelectionResult.js';
             return undefined;
         }
 
+        var tileWithMesh = tile;
+
         while (tile._lastSelectionResult === TileSelectionResult.REFINED) {
             tile = tileIfContainsCartographic(tile.southwestChild, cartographic) ||
                    tileIfContainsCartographic(tile.southeastChild, cartographic) ||
                    tileIfContainsCartographic(tile.northwestChild, cartographic) ||
                    tile.northeastChild;
+            if (defined(tile.data) && defined(tile.data.renderedMesh)) {
+                tileWithMesh = tile;
+            }
         }
 
+        tile = tileWithMesh;
+
         // This tile was either rendered or culled.
         // It is sometimes useful to get a height from a culled tile,
         // e.g. when we're getting a height in order to place a billboard
         // on terrain, and the camera is looking at that same billboard.
         // The culled tile must have a valid mesh, though.
-        if (!defined(tile.data) || !defined(tile.data.renderedMesh)) {
+        if (!defined(tile)) {
             // Tile was not rendered (culled).
             return undefined;
         }
diff --git a/Source/Scene/ScreenSpaceCameraController.js b/Source/Scene/ScreenSpaceCameraController.js
index 6a9278ac11d3..8f37739d2356 100644
--- a/Source/Scene/ScreenSpaceCameraController.js
+++ b/Source/Scene/ScreenSpaceCameraController.js
@@ -266,6 +266,7 @@ import TweenCollection from './TweenCollection.js';
         this._strafing = false;
         this._zoomingOnVector = false;
         this._rotatingZoom = false;
+        this._adjustedHeightForTerrain = false;
 
         var projection = scene.mapProjection;
         this._maxCoord = projection.project(new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO));
@@ -1137,7 +1138,10 @@ import TweenCollection from './TweenCollection.js';
         controller._rotateRateRangeAdjustment = radius;
 
         var originalPosition = Cartesian3.clone(camera.positionWC, rotateCVCartesian3);
-        camera._adjustHeightForTerrain();
+
+        if (controller.enableCollisionDetection) {
+            adjustHeightForTerrain(controller);
+        }
 
         if (!Cartesian3.equals(camera.positionWC, originalPosition)) {
             camera._setTransform(verticalTransform);
@@ -1766,7 +1770,10 @@ import TweenCollection from './TweenCollection.js';
         controller._rotateRateRangeAdjustment = radius;
 
         var originalPosition = Cartesian3.clone(camera.positionWC, tilt3DCartesian3);
-        camera._adjustHeightForTerrain();
+
+        if (controller.enableCollisionDetection) {
+            adjustHeightForTerrain(controller);
+        }
 
         if (!Cartesian3.equals(camera.positionWC, originalPosition)) {
             camera._setTransform(verticalTransform);
@@ -1918,11 +1925,78 @@ import TweenCollection from './TweenCollection.js';
         reactToInput(controller, controller.enableLook, controller.lookEventTypes, look3D);
     }
 
+    var scratchAdjustHeightTransform = new Matrix4();
+    var scratchAdjustHeightCartographic = new Cartographic();
+
+    function adjustHeightForTerrain(controller) {
+        controller._adjustedHeightForTerrain = true;
+
+        var scene = controller._scene;
+        var mode = scene.mode;
+        var globe = scene.globe;
+
+        if (!defined(globe) || mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
+            return;
+        }
+
+        var camera = scene.camera;
+        var ellipsoid = globe.ellipsoid;
+        var projection = scene.mapProjection;
+
+        var transform;
+        var mag;
+        if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) {
+            transform = Matrix4.clone(camera.transform, scratchAdjustHeightTransform);
+            mag = Cartesian3.magnitude(camera.position);
+            camera._setTransform(Matrix4.IDENTITY);
+        }
+
+        var cartographic = scratchAdjustHeightCartographic;
+        if (mode === SceneMode.SCENE3D) {
+            ellipsoid.cartesianToCartographic(camera.position, cartographic);
+        } else {
+            projection.unproject(camera.position, cartographic);
+        }
+
+        var heightUpdated = false;
+        if (cartographic.height < controller._minimumCollisionTerrainHeight) {
+            var height = globe.getHeight(cartographic);
+            if (defined(height)) {
+                height += controller.minimumZoomDistance;
+                if (cartographic.height < height) {
+                    cartographic.height = height;
+                    if (mode === SceneMode.SCENE3D) {
+                        ellipsoid.cartographicToCartesian(cartographic, camera.position);
+                    } else {
+                        projection.project(cartographic, camera.position);
+                    }
+                    heightUpdated = true;
+                }
+            }
+        }
+
+        if (defined(transform)) {
+            camera._setTransform(transform);
+            if (heightUpdated) {
+                Cartesian3.normalize(camera.position, camera.position);
+                Cartesian3.negate(camera.position, camera.direction);
+                Cartesian3.multiplyByScalar(camera.position, Math.max(mag, controller.minimumZoomDistance), camera.position);
+                Cartesian3.normalize(camera.direction, camera.direction);
+                Cartesian3.cross(camera.direction, camera.up, camera.right);
+                Cartesian3.cross(camera.right, camera.direction, camera.up);
+            }
+        }
+    }
+
+    var scratchPreviousPosition = new Cartesian3();
+    var scratchPreviousDirection = new Cartesian3();
+
     /**
      * @private
      */
     ScreenSpaceCameraController.prototype.update = function() {
-        if (!Matrix4.equals(this._scene.camera.transform, Matrix4.IDENTITY)) {
+        var camera = this._scene.camera;
+        if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) {
             this._globe = undefined;
             this._ellipsoid = Ellipsoid.UNIT_SPHERE;
         } else {
@@ -1938,6 +2012,10 @@ import TweenCollection from './TweenCollection.js';
         this._rotateFactor = 1.0 / radius;
         this._rotateRateRangeAdjustment = radius;
 
+        this._adjustedHeightForTerrain = false;
+        var previousPosition = Cartesian3.clone(camera.positionWC, scratchPreviousPosition);
+        var previousDirection = Cartesian3.clone(camera.directionWC, scratchPreviousDirection);
+
         var scene = this._scene;
         var mode = scene.mode;
         if (mode === SceneMode.SCENE2D) {
@@ -1950,6 +2028,14 @@ import TweenCollection from './TweenCollection.js';
             update3D(this);
         }
 
+        if (this.enableCollisionDetection && !this._adjustedHeightForTerrain) {
+            // Adjust the camera height if the camera moved at all (user input or intertia) and an action didn't already adjust the camera height
+            var cameraChanged = !Cartesian3.equals(previousPosition, camera.positionWC) || !Cartesian3.equals(previousDirection, camera.directionWC);
+            if (cameraChanged) {
+                adjustHeightForTerrain(this);
+            }
+        }
+
         this._aggregator.reset();
     };
 
diff --git a/Specs/Scene/ScreenSpaceCameraControllerSpec.js b/Specs/Scene/ScreenSpaceCameraControllerSpec.js
index 8f92738f9bf4..de412812ac00 100644
--- a/Specs/Scene/ScreenSpaceCameraControllerSpec.js
+++ b/Specs/Scene/ScreenSpaceCameraControllerSpec.js
@@ -1024,18 +1024,18 @@ describe('Scene/ScreenSpaceCameraController', function() {
         moveMouse(MouseButtons.LEFT, startPosition, endPosition);
         updateController();
 
-        expect(camera.position).toEqual(position);
-        expect(camera.direction).toEqual(direction);
-        expect(camera.up).toEqual(up);
-        expect(camera.right).toEqual(right);
+        expect(camera.position).toEqualEpsilon(position, CesiumMath.EPSILON7);
+        expect(camera.direction).toEqualEpsilon(direction, CesiumMath.EPSILON7);
+        expect(camera.up).toEqualEpsilon(up, CesiumMath.EPSILON7);
+        expect(camera.right).toEqualEpsilon(right, CesiumMath.EPSILON7);
 
         controller.enableRotate = true;
         updateController();
 
-        expect(camera.position).toEqual(position);
-        expect(camera.direction).toEqual(direction);
-        expect(camera.up).toEqual(up);
-        expect(camera.right).toEqual(right);
+        expect(camera.position).toEqualEpsilon(position, CesiumMath.EPSILON7);
+        expect(camera.direction).toEqualEpsilon(direction, CesiumMath.EPSILON7);
+        expect(camera.up).toEqualEpsilon(up, CesiumMath.EPSILON7);
+        expect(camera.right).toEqualEpsilon(right, CesiumMath.EPSILON7);
     });
 
     it('can set input type to undefined', function() {
@@ -1101,12 +1101,17 @@ describe('Scene/ScreenSpaceCameraController', function() {
         updateController();
 
         camera.setView({
-            destination : Cartesian3.fromDegrees(-72.0, 40.0, 1.0)
+            destination : Cartesian3.fromDegrees(-72.0, 40.0, -10.0)
         });
 
+        // Trigger terrain adjustment with a small mouse movement
+        var startPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 4);
+        var endPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
+        moveMouse(MouseButtons.RIGHT, startPosition, endPosition);
+
         updateController();
 
-        expect(camera.positionCartographic.height).toEqualEpsilon(controller.minimumZoomDistance, CesiumMath.EPSILON7);
+        expect(camera.positionCartographic.height).toEqualEpsilon(controller.minimumZoomDistance, CesiumMath.EPSILON5);
     });
 
     it('camera does not go below the terrain in CV', function() {
@@ -1116,9 +1121,14 @@ describe('Scene/ScreenSpaceCameraController', function() {
         updateController();
 
         camera.setView({
-            destination : Cartesian3.fromDegrees(-72.0, 40.0, 1.0)
+            destination : Cartesian3.fromDegrees(-72.0, 40.0, -10.0)
         });
 
+        // Trigger terrain adjustment with a small mouse movement
+        var startPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 4);
+        var endPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
+        moveMouse(MouseButtons.RIGHT, startPosition, endPosition);
+
         updateController();
 
         expect(camera.position.z).toEqualEpsilon(controller.minimumZoomDistance, CesiumMath.EPSILON7);
@@ -1135,6 +1145,11 @@ describe('Scene/ScreenSpaceCameraController', function() {
             destination : Cartesian3.fromDegrees(-72.0, 40.0, -10.0)
         });
 
+        // Trigger terrain adjustment with a small mouse movement
+        var startPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 4);
+        var endPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
+        moveMouse(MouseButtons.RIGHT, startPosition, endPosition);
+
         updateController();
 
         expect(camera.positionCartographic.height).toBeLessThan(controller.minimumZoomDistance);
@@ -1151,6 +1166,11 @@ describe('Scene/ScreenSpaceCameraController', function() {
             destination : Cartesian3.fromDegrees(-72.0, 40.0, -10.0)
         });
 
+        // Trigger terrain adjustment with a small mouse movement
+        var startPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 4);
+        var endPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
+        moveMouse(MouseButtons.RIGHT, startPosition, endPosition);
+
         updateController();
 
         expect(camera.position.z).toBeLessThan(controller.minimumZoomDistance);
@@ -1164,6 +1184,11 @@ describe('Scene/ScreenSpaceCameraController', function() {
 
         camera.lookAt(Cartesian3.fromDegrees(-72.0, 40.0, 1.0), new Cartesian3(1.0, 1.0, -10.0));
 
+        // Trigger terrain adjustment with a small mouse movement
+        var startPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 4);
+        var endPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
+        moveMouse(MouseButtons.RIGHT, startPosition, endPosition);
+
         updateController();
 
         expect(camera.positionCartographic.height).toBeGreaterThanOrEqualTo(controller.minimumZoomDistance);
@@ -1177,6 +1202,11 @@ describe('Scene/ScreenSpaceCameraController', function() {
 
         camera.lookAt(Cartesian3.fromDegrees(-72.0, 40.0, 1.0), new Cartesian3(1.0, 1.0, -10.0));
 
+        // Trigger terrain adjustment with a small mouse movement
+        var startPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 4);
+        var endPosition = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
+        moveMouse(MouseButtons.RIGHT, startPosition, endPosition);
+
         updateController();
 
         expect(camera.positionWC.x).toEqualEpsilon(controller.minimumZoomDistance, CesiumMath.EPSILON8);