diff --git a/lib/sqlite3.d.ts b/lib/sqlite3.d.ts
index b27b0cf51..9f57a673d 100644
--- a/lib/sqlite3.d.ts
+++ b/lib/sqlite3.d.ts
@@ -93,12 +93,26 @@ export class Statement extends events.EventEmitter {
     each(...params: any[]): this;
 }
 
+export class Backup extends events.EventEmitter {
+    step(pages: number, callback?: (error: Error, backup: Backup) => void): Backup;
+    finish(callback?: (error: Error, backup: Backup) => void): Backup;
+
+    get idle(): boolean;
+    get completed(): boolean;
+    get failed(): boolean;
+    get remaining(): number;
+    get pageCount(): number;
+}
+
 export class Database extends events.EventEmitter {
     constructor(filename: string, callback?: (err: Error | null) => void);
     constructor(filename: string, mode?: number, callback?: (err: Error | null) => void);
 
     close(callback?: (err: Error | null) => void): void;
 
+    backup(destination: string | Database, destName: string, sourceName: string, filenameIsDest = true, callback?: (this: Backup, err: Error | null, backup: Backup) => void): this;
+    backup(destination: string | Database, callback?: (this: Backup, err: Error | null, backup: Backup) => void): this;
+
     run(sql: string, callback?: (this: RunResult, err: Error | null) => void): this;
     run(sql: string, params: any, callback?: (this: RunResult, err: Error | null) => void): this;
     run(sql: string, ...params: any[]): this;
@@ -201,5 +215,6 @@ export interface sqlite3 {
     RunResult: RunResult;
     Statement: typeof Statement;
     Database: typeof Database;
+    Backup: typeof Backup;
     verbose(): this;
 }
\ No newline at end of file
diff --git a/src/backup.cc b/src/backup.cc
index 9f3893b96..cb1a85eb5 100644
--- a/src/backup.cc
+++ b/src/backup.cc
@@ -133,8 +133,8 @@ Backup::Backup(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Backup>(info)
         Napi::TypeError::New(env, "Database object expected").ThrowAsJavaScriptException();
         return;
     }
-    else if (length <= 1 || !info[1].IsString()) {
-        Napi::TypeError::New(env, "Filename expected").ThrowAsJavaScriptException();
+    else if (length <= 1 || !(info[1].IsString() || info[1].IsObject())) {
+        Napi::TypeError::New(env, "Filename or database object expected").ThrowAsJavaScriptException();
         return;
     }
     else if (length <= 2 || !info[2].IsString()) {
@@ -155,7 +155,20 @@ Backup::Backup(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Backup>(info)
     }
 
     Database* db = Napi::ObjectWrap<Database>::Unwrap(info[0].As<Napi::Object>());
-    Napi::String filename = info[1].As<Napi::String>();
+    Database* otherDb = NULL;
+
+    Napi::String filename;
+
+    if (info[1].IsObject()) {
+        // A database instance was passed instead of a filename
+        otherDb = Napi::ObjectWrap<Database>::Unwrap(info[1].As<Napi::Object>());
+        otherDb->Ref();
+
+        filename = Napi::String::New(env, "<sqlite3 instance>");
+    } else {
+        filename = info[1].As<Napi::String>();
+    }
+
     Napi::String sourceName = info[2].As<Napi::String>();
     Napi::String destName = info[3].As<Napi::String>();
     Napi::Boolean filenameIsDest = info[4].As<Napi::Boolean>();
@@ -165,14 +178,28 @@ Backup::Backup(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Backup>(info)
     info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("destName", destName));
     info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filenameIsDest", filenameIsDest));
 
-    init(db);
+    init(db, otherDb);
 
     InitializeBaton* baton = new InitializeBaton(db, info[5].As<Napi::Function>(), this);
+    baton->otherDb = otherDb;
     baton->filename = filename.Utf8Value();
     baton->sourceName = sourceName.Utf8Value();
     baton->destName = destName.Utf8Value();
     baton->filenameIsDest = filenameIsDest.Value();
-    db->Schedule(Work_BeginInitialize, baton);
+
+    if (otherDb) {
+        otherDb->Schedule(Work_BeforeInitialize, baton, true);
+    } else {
+        db->Schedule(Work_BeginInitialize, baton);
+    }
+}
+
+void Backup::Work_BeforeInitialize(Database::Baton* baton) {
+    InitializeBaton *initBaton = static_cast<InitializeBaton *>(baton);
+    // at this point, the target database object is locked (it is
+    // important that its database connection remains unused).
+    initBaton->otherDb->pending++;
+    baton->db->Schedule(Work_BeginInitialize, baton);
 }
 
 void Backup::Work_BeginInitialize(Database::Baton* baton) {
@@ -195,22 +222,37 @@ void Backup::Work_Initialize(napi_env e, void* data) {
     sqlite3_mutex* mtx = sqlite3_db_mutex(baton->db->_handle);
     sqlite3_mutex_enter(mtx);
 
-    backup->status = sqlite3_open(baton->filename.c_str(), &backup->_otherDb);
+    backup->message = "";
+    if (baton->otherDb) {
+        // If another database instance was passed,
+        // link other (locked) db to the backup state
+        backup->otherDb = baton->otherDb;
+        backup->_otherDbHandle = baton->otherDb->_handle;
+
+        backup->status = SQLITE_OK;
+        if (!baton->filenameIsDest) {
+            backup->status = SQLITE_MISUSE;
+            backup->message = "do not toggle filenameIsDest when backing up between sqlite3.Database instances";
+        }
+    } else {
+        // Do not initialize otherDb and continue with normal
+        // initialization by using the filename that was provided
+        backup->otherDb = NULL;
+        backup->status = sqlite3_open(baton->filename.c_str(), &backup->_otherDbHandle);
+    }
 
     if (backup->status == SQLITE_OK) {
         backup->_handle = sqlite3_backup_init(
-            baton->filenameIsDest ? backup->_otherDb : backup->db->_handle,
+            baton->filenameIsDest ? backup->_otherDbHandle : backup->db->_handle,
             baton->destName.c_str(),
-            baton->filenameIsDest ? backup->db->_handle : backup->_otherDb,
+            baton->filenameIsDest ? backup->db->_handle : backup->_otherDbHandle,
             baton->sourceName.c_str());
     }
-    backup->_destDb = baton->filenameIsDest ? backup->_otherDb : backup->db->_handle;
+    backup->_destDbHandle = baton->filenameIsDest ? backup->_otherDbHandle : backup->db->_handle;
 
     if (backup->status != SQLITE_OK) {
-        backup->message = std::string(sqlite3_errmsg(backup->_destDb));
-        sqlite3_close(backup->_otherDb);
-        backup->_otherDb = NULL;
-        backup->_destDb = NULL;
+        if (backup->message == "") backup->message = std::string(sqlite3_errmsg(backup->_destDbHandle));
+        backup->FinishSqlite();
     }
 
     sqlite3_mutex_leave(mtx);
@@ -231,8 +273,8 @@ void Backup::Work_AfterInitialize(napi_env e, napi_status status, void* data) {
         backup->inited = true;
         Napi::Function cb = baton->callback.Value();
         if (!cb.IsEmpty() && cb.IsFunction()) {
-            Napi::Value argv[] = { env.Null() };
-            TRY_CATCH_CALL(backup->Value(), cb, 1, argv);
+            Napi::Value argv[] = { env.Null(), backup->Value() };
+            TRY_CATCH_CALL(backup->Value(), cb, 2, argv);
         }
     }
     BACKUP_END();
@@ -354,6 +396,14 @@ void Backup::FinishAll() {
     CleanQueue();
     FinishSqlite();
     db->Unref();
+
+    if (otherDb) {
+        assert(otherDb->locked);
+        otherDb->pending--;
+        otherDb->Process();
+        otherDb->Unref();
+        otherDb = NULL;
+    }    
 }
 
 void Backup::FinishSqlite() {
@@ -361,11 +411,15 @@ void Backup::FinishSqlite() {
         sqlite3_backup_finish(_handle);
         _handle = NULL;
     }
-    if (_otherDb) {
-        sqlite3_close(_otherDb);
-        _otherDb = NULL;
+    if (_otherDbHandle) {
+        if (!otherDb) {
+            // Only close the database if it was
+            // not passed as a descriptor already.
+            sqlite3_close(_otherDbHandle);
+        }
+        _otherDbHandle = NULL;
     }
-    _destDb = NULL;
+    _destDbHandle = NULL;
 }
 
 Napi::Value Backup::IdleGetter(const Napi::CallbackInfo& info) {
diff --git a/src/backup.h b/src/backup.h
index c15b77bfe..e3387678a 100644
--- a/src/backup.h
+++ b/src/backup.h
@@ -113,6 +113,7 @@ class Backup : public Napi::ObjectWrap<Backup> {
 
     struct InitializeBaton : Database::Baton {
         Backup* backup;
+        Database* otherDb;
         std::string filename;
         std::string sourceName;
         std::string destName;
@@ -145,11 +146,12 @@ class Backup : public Napi::ObjectWrap<Backup> {
         Baton* baton;
     };
 
-    void init(Database* db_) {
+    void init(Database* db_, Database* otherDb_) {
         db = db_;
+        otherDb = otherDb_;
         _handle = NULL;
-        _otherDb = NULL;
-        _destDb = NULL;
+        _otherDbHandle = NULL;
+        _destDbHandle = NULL;
         inited = false;
         locked = true;
         completed = false;
@@ -183,6 +185,7 @@ class Backup : public Napi::ObjectWrap<Backup> {
     void RetryErrorSetter(const Napi::CallbackInfo& info, const Napi::Value& value);
 
 protected:
+    static void Work_BeforeInitialize(Database::Baton* baton);
     static void Work_BeginInitialize(Database::Baton* baton);
     static void Work_Initialize(napi_env env, void* data);
     static void Work_AfterInitialize(napi_env env, napi_status status, void* data);
@@ -197,10 +200,11 @@ class Backup : public Napi::ObjectWrap<Backup> {
     void GetRetryErrors(std::set<int>& retryErrorsSet);
 
     Database* db;
+    Database* otherDb;
 
     sqlite3_backup* _handle;
-    sqlite3* _otherDb;
-    sqlite3* _destDb;
+    sqlite3* _otherDbHandle;
+    sqlite3* _destDbHandle;
     int status;
     std::string message;
 
diff --git a/test/backup.test.js b/test/backup.test.js
index c05c298f8..e9d99eb30 100644
--- a/test/backup.test.js
+++ b/test/backup.test.js
@@ -276,4 +276,55 @@ describe('backup', function() {
             });
         });
     });
+
+    it ('can backup between two sqlite3.Database instances', function(done) {
+        var src = new sqlite3.Database(':memory:', function(err) {
+            if (err) throw err;
+            src.exec("CREATE TABLE space (txt TEXT)", function(err) {
+                if (err) throw err;
+                src.exec("INSERT INTO space(txt) VALUES('monkey')", function(err) {
+                    if (err) throw err;
+                    var dest = new sqlite3.Database(':memory:', function(err) {
+                        if (err) throw err;
+                        var backup = src.backup(dest);
+                        backup.step(-1);
+                        backup.finish(function(err) {
+                            if (err) throw err;
+                            assertRowsMatchDb(src, 'space', dest, 'space', done);
+                        });
+                    });
+                });
+            });
+        });
+    });
+
+    it ('locks destination when backing up between two sqlite3.Database instances', function(done) {
+        var src = new sqlite3.Database(':memory:', function(err) {
+            if (err) throw err;
+            src.exec("CREATE TABLE space (txt TEXT)", function(err) {
+                if (err) throw err;
+                src.exec("INSERT INTO space(txt) VALUES('monkey')", function(err) {
+                    if (err) throw err;
+                    var dest = new sqlite3.Database(':memory:', function(err) {
+                        if (err) throw err;
+                        var backup = src.backup(dest, function(err) {
+                            if (err) throw err;
+                            var finished = false;
+                            // This action on dest db should be held until backup finishes.
+                            dest.exec("CREATE TABLE space2 (txt TEXT)", function(err) {
+                                if (err) throw err;
+                                assert(finished);
+                                done();
+                            });
+                            backup.step(-1);
+                            backup.finish(function(err) {
+                                if (err) throw err;
+                                finished = true;
+                            });
+                        });
+                    });
+                });
+            });
+        });
+    });
 });