diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 8e39644846da09226640f39f8f8600bad540eb5a..c32e3ae9182871d4aa588deec2d8b22c932783e3 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -139,8 +139,11 @@ void Server::Init(Handle<Object> exports) {
   NanSetPrototypeTemplate(tpl, "start",
                           NanNew<FunctionTemplate>(Start)->GetFunction());
 
-  NanSetPrototypeTemplate(tpl, "shutdown",
-                          NanNew<FunctionTemplate>(Shutdown)->GetFunction());
+  NanSetPrototypeTemplate(tpl, "tryShutdown",
+                          NanNew<FunctionTemplate>(TryShutdown)->GetFunction());
+  NanSetPrototypeTemplate(
+      tpl, "forceShutdown",
+      NanNew<FunctionTemplate>(ForceShutdown)->GetFunction());
 
   NanAssignPersistent(fun_tpl, tpl);
   Handle<Function> ctr = tpl->GetFunction();
@@ -153,14 +156,13 @@ bool Server::HasInstance(Handle<Value> val) {
 }
 
 void Server::ShutdownServer() {
-  if (this->wrapped_server != NULL) {
-    grpc_server_shutdown_and_notify(this->wrapped_server,
-                                    this->shutdown_queue,
-                                    NULL);
-    grpc_completion_queue_pluck(this->shutdown_queue, NULL,
-                                gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-    this->wrapped_server = NULL;
-  }
+  grpc_server_shutdown_and_notify(this->wrapped_server,
+                                  this->shutdown_queue,
+                                  NULL);
+  grpc_server_cancel_all_calls(this->wrapped_server);
+  grpc_completion_queue_pluck(this->shutdown_queue, NULL,
+                              gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  this->wrapped_server = NULL;
 }
 
 NAN_METHOD(Server::New) {
@@ -222,9 +224,6 @@ NAN_METHOD(Server::RequestCall) {
     return NanThrowTypeError("requestCall can only be called on a Server");
   }
   Server *server = ObjectWrap::Unwrap<Server>(args.This());
-  if (server->wrapped_server == NULL) {
-    return NanThrowError("requestCall cannot be called on a shut down Server");
-  }
   NewCallOp *op = new NewCallOp();
   unique_ptr<OpVec> ops(new OpVec());
   ops->push_back(unique_ptr<Op>(op));
@@ -256,10 +255,6 @@ NAN_METHOD(Server::AddHttp2Port) {
         "addHttp2Port's second argument must be ServerCredentials");
   }
   Server *server = ObjectWrap::Unwrap<Server>(args.This());
-  if (server->wrapped_server == NULL) {
-    return NanThrowError(
-        "addHttp2Port cannot be called on a shut down Server");
-  }
   ServerCredentials *creds_object = ObjectWrap::Unwrap<ServerCredentials>(
       args[1]->ToObject());
   grpc_server_credentials *creds = creds_object->GetWrappedServerCredentials();
@@ -281,21 +276,30 @@ NAN_METHOD(Server::Start) {
     return NanThrowTypeError("start can only be called on a Server");
   }
   Server *server = ObjectWrap::Unwrap<Server>(args.This());
-  if (server->wrapped_server == NULL) {
-    return NanThrowError("start cannot be called on a shut down Server");
-  }
   grpc_server_start(server->wrapped_server);
   NanReturnUndefined();
 }
 
-NAN_METHOD(ShutdownCallback) {
+NAN_METHOD(Server::TryShutdown) {
+  NanScope();
+  if (!HasInstance(args.This())) {
+    return NanThrowTypeError("tryShutdown can only be called on a Server");
+  }
+  Server *server = ObjectWrap::Unwrap<Server>(args.This());
+  unique_ptr<OpVec> ops(new OpVec());
+  grpc_server_shutdown_and_notify(
+      server->wrapped_server,
+      CompletionQueueAsyncWorker::GetQueue(),
+      new struct tag(new NanCallback(args[0].As<Function>()), ops.release(),
+                     shared_ptr<Resources>(nullptr)));
+  CompletionQueueAsyncWorker::Next();
   NanReturnUndefined();
 }
 
-NAN_METHOD(Server::Shutdown) {
+NAN_METHOD(Server::ForceShutdown) {
   NanScope();
   if (!HasInstance(args.This())) {
-    return NanThrowTypeError("shutdown can only be called on a Server");
+    return NanThrowTypeError("forceShutdown can only be called on a Server");
   }
   Server *server = ObjectWrap::Unwrap<Server>(args.This());
   server->ShutdownServer();
diff --git a/src/node/ext/server.h b/src/node/ext/server.h
index faab7e3418c649aa5e768fd9edcf329fa9ebf607..e7d5c3fb11a253197a897ca0a4a38518d1de3ec0 100644
--- a/src/node/ext/server.h
+++ b/src/node/ext/server.h
@@ -67,7 +67,8 @@ class Server : public ::node::ObjectWrap {
   static NAN_METHOD(RequestCall);
   static NAN_METHOD(AddHttp2Port);
   static NAN_METHOD(Start);
-  static NAN_METHOD(Shutdown);
+  static NAN_METHOD(TryShutdown);
+  static NAN_METHOD(ForceShutdown);
   static NanCallback *constructor;
   static v8::Persistent<v8::FunctionTemplate> fun_tpl;
 
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 8b86173f082c56af90a4fd20c7c02a5416d684ec..f2520c3c9703bf061d2445ba08c6dd7bfc7e31f5 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -613,11 +613,26 @@ function Server(options) {
     }
     server.requestCall(handleNewCall);
   };
+
+  /**
+   * Gracefully shuts down the server. The server will stop receiving new calls,
+   * and any pending calls will complete. The callback will be called when all
+   * pending calls have completed and the server is fully shut down. This method
+   * is idempotent with itself and forceShutdown.
+   * @param {function()} callback The shutdown complete callback
+   */
+  this.tryShutdown = function(callback) {
+    server.tryShutdown(callback);
+  };
+
   /**
-   * Shuts down the server.
+   * Forcibly shuts down the server. The server will stop receiving new calls
+   * and cancel all pending calls. When it returns, the server has shut down.
+   * This method is idempotent with itself and tryShutdown, and it will trigger
+   * any outstanding tryShutdown callbacks.
    */
-  this.shutdown = function() {
-    server.shutdown();
+  this.forceShutdown = function() {
+    server.forceShutdown();
   };
 }
 
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index 8d0f20b074736be68cef9914e3ff34eeeda62422..e7f071bcd537699a892d9fdac608e473de3a2264 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -61,7 +61,7 @@ describe('call', function() {
     channel = new grpc.Channel('localhost:' + port, insecureCreds);
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   describe('constructor', function() {
     it('should reject anything less than 3 arguments', function() {
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index 7574d98b8af7ff92b826f113c581cf94da7cedb6..4b8da3bfb171172bfee92fb023632aa17814046d 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -70,7 +70,7 @@ describe('end-to-end', function() {
     channel = new grpc.Channel('localhost:' + port_num, insecureCreds);
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   it('should start and end a request without error', function(complete) {
     var done = multiDone(complete, 2);
diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js
index be4ef1d251b547b5bd0a4f8a442976088831bc84..22c58d3956b613930d3d827b62ac2864c9d4d0a0 100644
--- a/src/node/test/health_test.js
+++ b/src/node/test/health_test.js
@@ -61,7 +61,7 @@ describe('Health Checking', function() {
                                      grpc.Credentials.createInsecure());
   });
   after(function() {
-    healthServer.shutdown();
+    healthServer.forceShutdown();
   });
   it('should say an enabled service is SERVING', function(done) {
     healthClient.check({service: ''}, function(err, response) {
diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js
index 0a5eb29c0c1a7e82ea2c6bbe8917f489b68befa5..2ca07c1d50d28a8e0f865327b87a89eeef4be0ef 100644
--- a/src/node/test/interop_sanity_test.js
+++ b/src/node/test/interop_sanity_test.js
@@ -51,7 +51,7 @@ describe('Interop tests', function() {
     done();
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   // This depends on not using a binary stream
   it('should pass empty_unary', function(done) {
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index ef01870a4c1dd0e83f91911870b7a4136b59a2bf..80b0c5ff2a989edb76b3347cace76645e6b1e16c 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -59,7 +59,7 @@ describe('Math client', function() {
     done();
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   it('should handle a single request', function(done) {
     var arg = {dividend: 7, divisor: 4};
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
index 20c9a07ffa37993f2c37cb3776f274644e5b9378..4670a62efa3037c2ffedd6f126f69e0be16aa9c2 100644
--- a/src/node/test/server_test.js
+++ b/src/node/test/server_test.js
@@ -90,7 +90,7 @@ describe('server', function() {
       server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure());
     });
     after(function() {
-      server.shutdown();
+      server.forceShutdown();
     });
     it('should start without error', function() {
       assert.doesNotThrow(function() {
@@ -98,4 +98,29 @@ describe('server', function() {
       });
     });
   });
+  describe('shutdown', function() {
+    var server;
+    beforeEach(function() {
+      server = new grpc.Server();
+      server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure());
+      server.start();
+    });
+    afterEach(function() {
+      server.forceShutdown();
+    });
+    it('tryShutdown should shutdown successfully', function(done) {
+      server.tryShutdown(done);
+    });
+    it.only('forceShutdown should shutdown successfully', function() {
+      server.forceShutdown();
+    });
+    it('tryShutdown should be idempotent', function(done) {
+      server.tryShutdown(done);
+      server.tryShutdown(function() {});
+    });
+    it('forceShutdown should be idempotent', function() {
+      server.forceShutdown();
+      server.forceShutdown();
+    });
+  });
 });
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 52515cc8e7ccf064646d84773f26e4ece74f7659..d12ba0465e98d6e65b7baa03bc4e27c7f891ce21 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -104,7 +104,7 @@ describe('Server.prototype.addProtoService', function() {
     server = new grpc.Server();
   });
   afterEach(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   it('Should succeed with a single service', function() {
     assert.doesNotThrow(function() {
@@ -148,7 +148,7 @@ describe('Client#$waitForReady', function() {
     client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   it('should complete when called alone', function(done) {
     client.$waitForReady(Infinity, function(error) {
@@ -203,7 +203,7 @@ describe('Echo service', function() {
     server.start();
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   it('should echo the recieved message directly', function(done) {
     client.echo({value: 'test value', value2: 3}, function(error, response) {
@@ -248,7 +248,7 @@ describe('Generic client and server', function() {
                           grpc.Credentials.createInsecure());
     });
     after(function() {
-      server.shutdown();
+      server.forceShutdown();
     });
     it('Should respond with a capitalized string', function(done) {
       client.capitalize('abc', function(err, response) {
@@ -296,7 +296,7 @@ describe('Echo metadata', function() {
     server.start();
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   it('with unary call', function(done) {
     var call = client.unary({}, function(err, data) {
@@ -419,7 +419,7 @@ describe('Other conditions', function() {
     server.start();
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   it('channel.getTarget should be available', function() {
     assert.strictEqual(typeof client.channel.getTarget(), 'string');
@@ -681,7 +681,7 @@ describe('Other conditions', function() {
     });
     afterEach(function() {
       console.log('Shutting down server');
-      proxy.shutdown();
+      proxy.forceShutdown();
     });
     describe('Cancellation', function() {
       it('With a unary call', function(done) {
@@ -845,7 +845,7 @@ describe('Cancelling surface client', function() {
     server.start();
   });
   after(function() {
-    server.shutdown();
+    server.forceShutdown();
   });
   it('Should correctly cancel a unary call', function(done) {
     var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) {