diff --git a/app.js b/app.js
index 4b4e176..5857864 100644
--- a/app.js
+++ b/app.js
@@ -501,4 +501,30 @@ process.on('uncaughtException', function (err) {
     logger.error(err);
     logger.error('Process will exit now.');
     process.exit(1);
+});
+
+// gracefully exit
+process.on('SIGINT', function () {
+    config.maintenance = true;
+    // disconnect all socket.io clients
+    Object.keys(io.sockets.sockets).forEach(function (key) {
+        var socket = io.sockets.sockets[key];
+        // notify client server going into maintenance status
+        socket.emit('maintenance', config.version);
+        socket.disconnect(true);
+    });
+    var checkCleanTimer = setInterval(function () {
+        var usersCount = Object.keys(realtime.users).length;
+        var notesCount = Object.keys(realtime.notes).length;
+        // check if all users and notes array are empty
+        if (usersCount == 0 && notesCount == 0) {
+            // close db connection
+            models.sequelize.close();
+            clearInterval(checkCleanTimer);
+            // wait for a while before exit
+            setTimeout(function () {
+                process.exit(0);
+            }, 100);
+        }
+    }, 100);
 });
\ No newline at end of file
diff --git a/lib/config.js b/lib/config.js
index 9f11c5b..5579d61 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -78,10 +78,12 @@ function getserverurl() {
 }
 
 var version = '0.4.0';
+var maintenance = config.maintenance || false;
 var cwd = path.join(__dirname, '..');
 
 module.exports = {
     version: version,
+    maintenance: maintenance,
     debug: debug,
     urlpath: urlpath,
     port: port,
diff --git a/lib/realtime.js b/lib/realtime.js
index a8bef97..1d14270 100644
--- a/lib/realtime.js
+++ b/lib/realtime.js
@@ -25,7 +25,9 @@ var realtime = {
     onAuthorizeFail: onAuthorizeFail,
     secure: secure,
     connection: connection,
-    getStatus: getStatus
+    getStatus: getStatus,
+    users: users,
+    notes: notes
 };
 
 function onAuthorizeSuccess(data, accept) {
@@ -70,8 +72,9 @@ function emitCheck(note) {
 }
 
 //actions
-var users = {};
-var notes = {};
+var users, notes;
+realtime.users = users = {};
+realtime.notes = notes = {};
 //update when the note is dirty
 var updater = setInterval(function () {
     async.each(Object.keys(notes), function (key, callback) {
@@ -536,6 +539,7 @@ function ifMayEdit(socket, callback) {
 }
 
 function connection(socket) {
+    if (config.maintenance) return;
     parseNoteIdFromSocket(socket, function (err, noteId) {
         if (err) {
             return failConnection(500, err, socket);
diff --git a/public/js/index.js b/public/js/index.js
index 1d6db92..4ac1b50 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -1825,6 +1825,11 @@ socket.on('error', function (data) {
     if (data.message && data.message.indexOf('AUTH failed') === 0)
         location.href = "./403";
 });
+var retryOnDisconnect = false;
+socket.on('maintenance', function (data) {
+    if (data == version)
+        retryOnDisconnect = true;
+});
 socket.on('disconnect', function (data) {
     showStatus(statusType.offline);
     if (loaded) {
@@ -1833,12 +1838,15 @@ socket.on('disconnect', function (data) {
     }
     if (!editor.getOption('readOnly'))
         editor.setOption('readOnly', true);
+    if (retryOnDisconnect)
+        socket.connect();
 });
 socket.on('reconnect', function (data) {
     //sync back any change in offline
     emitUserStatus(true);
     cursorActivity();
     socket.emit('online users');
+    retryOnDisconnect = false;
 });
 socket.on('connect', function (data) {
     personalInfo['id'] = socket.id;