diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -140,6 +140,7 @@
     QAction *usedReceivingAddressesAction = nullptr;
     QAction *signMessageAction = nullptr;
     QAction *verifyMessageAction = nullptr;
+    QAction *m_load_psbt_action = nullptr;
     QAction *aboutAction = nullptr;
     QAction *receiveCoinsAction = nullptr;
     QAction *receiveCoinsMenuAction = nullptr;
@@ -282,6 +283,8 @@
     void gotoSignMessageTab(QString addr = "");
     /** Show Sign/Verify Message dialog and switch to verify message tab */
     void gotoVerifyMessageTab(QString addr = "");
+    /** Show load Partially Signed Bitcoin Transaction dialog */
+    void gotoLoadPSBT();
 
     /** Show open dialog */
     void openClicked();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -364,6 +364,9 @@
     verifyMessageAction->setStatusTip(
         tr("Verify messages to ensure they were signed with specified Bitcoin "
            "addresses"));
+    m_load_psbt_action = new QAction(tr("Load PSBT..."), this);
+    m_load_psbt_action->setStatusTip(
+        tr("Load Partially Signed Bitcoin Transaction"));
 
     openRPCConsoleAction =
         new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"),
@@ -443,6 +446,8 @@
                 [this] { showNormalIfMinimized(); });
         connect(verifyMessageAction, &QAction::triggered,
                 [this] { gotoVerifyMessageTab(); });
+        connect(m_load_psbt_action, &QAction::triggered,
+                [this] { gotoLoadPSBT(); });
         connect(usedSendingAddressesAction, &QAction::triggered, walletFrame,
                 &WalletFrame::usedSendingAddresses);
         connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame,
@@ -530,6 +535,7 @@
         file->addAction(backupWalletAction);
         file->addAction(signMessageAction);
         file->addAction(verifyMessageAction);
+        file->addAction(m_load_psbt_action);
         file->addSeparator();
     }
     file->addAction(quitAction);
@@ -967,6 +973,11 @@
         walletFrame->gotoVerifyMessageTab(addr);
     }
 }
+void BitcoinGUI::gotoLoadPSBT() {
+    if (walletFrame) {
+        walletFrame->gotoLoadPSBT();
+    }
+}
 #endif // ENABLE_WALLET
 
 void BitcoinGUI::updateNetworkState() {
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -79,6 +79,9 @@
     /** Show Sign/Verify Message dialog and switch to verify message tab */
     void gotoVerifyMessageTab(QString addr = "");
 
+    /** Load Partially Signed Bitcoin Transaction */
+    void gotoLoadPSBT();
+
     /** Encrypt the wallet */
     void encryptWallet(bool status);
     /** Backup the wallet */
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -153,6 +153,13 @@
     }
 }
 
+void WalletFrame::gotoLoadPSBT() {
+    WalletView *walletView = currentWalletView();
+    if (walletView) {
+        walletView->gotoLoadPSBT();
+    }
+}
+
 void WalletFrame::encryptWallet(bool status) {
     WalletView *walletView = currentWalletView();
     if (walletView) {
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -89,6 +89,8 @@
     void gotoSignMessageTab(QString addr = "");
     /** Show Sign/Verify Message dialog and switch to verify message tab */
     void gotoVerifyMessageTab(QString addr = "");
+    /** Load Partially Signed Bitcoin Transaction */
+    void gotoLoadPSBT();
 
     /**
      * Show incoming transaction notification for new transactions.
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -4,7 +4,11 @@
 
 #include <qt/walletview.h>
 
+#include <config.h> // For GetConfig
 #include <interfaces/node.h>
+#include <node/psbt.h>
+#include <node/transaction.h>
+#include <policy/policy.h>
 #include <qt/addressbookpage.h>
 #include <qt/askpassphrasedialog.h>
 #include <qt/bitcoingui.h>
@@ -20,6 +24,7 @@
 #include <qt/transactionview.h>
 #include <qt/walletmodel.h>
 #include <ui_interface.h>
+#include <util/strencodings.h>
 
 #include <QAction>
 #include <QActionGroup>
@@ -257,6 +262,101 @@
     }
 }
 
+void WalletView::gotoLoadPSBT() {
+    QString filename = GUIUtil::getOpenFileName(
+        this, tr("Load Transaction Data"), QString(),
+        tr("Partially Signed Transaction (*.psbt)"), nullptr);
+    if (filename.isEmpty()) {
+        return;
+    }
+    if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) ==
+        MAX_FILE_SIZE_PSBT) {
+        Q_EMIT message(tr("Error"),
+                       tr("PSBT file must be smaller than 100 MiB"),
+                       CClientUIInterface::MSG_ERROR);
+        return;
+    }
+    std::ifstream in(filename.toLocal8Bit().data(), std::ios::binary);
+    std::string dataStr(std::istreambuf_iterator<char>{in}, {});
+
+    std::string error;
+    PartiallySignedTransaction psbtx;
+    if (!DecodeRawPSBT(psbtx, dataStr, error)) {
+        Q_EMIT message(tr("Error"),
+                       tr("Unable to decode PSBT file") + "\n" +
+                           QString::fromStdString(error),
+                       CClientUIInterface::MSG_ERROR);
+        return;
+    }
+
+    CMutableTransaction mtx;
+    bool complete = false;
+    PSBTAnalysis analysis = AnalyzePSBT(psbtx);
+    QMessageBox msgBox;
+    msgBox.setText("PSBT");
+    switch (analysis.next) {
+        case PSBTRole::CREATOR:
+        case PSBTRole::UPDATER:
+            msgBox.setInformativeText(
+                "PSBT is incomplete. Copy to clipboard for manual inspection?");
+            break;
+        case PSBTRole::SIGNER:
+            msgBox.setInformativeText(
+                "Transaction needs more signatures. Copy to clipboard?");
+            break;
+        case PSBTRole::FINALIZER:
+        case PSBTRole::EXTRACTOR:
+            complete = FinalizeAndExtractPSBT(psbtx, mtx);
+            if (complete) {
+                msgBox.setInformativeText(
+                    tr("Would you like to send this transaction?"));
+            } else {
+                // The analyzer missed something, e.g. if there are
+                // final_scriptSig but with invalid signatures.
+                msgBox.setInformativeText(
+                    tr("There was an unexpected problem processing the PSBT. "
+                       "Copy to clipboard for manual inspection?"));
+            }
+    }
+
+    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
+    switch (msgBox.exec()) {
+        case QMessageBox::Yes: {
+            if (complete) {
+                std::string err_string;
+                CTransactionRef tx = MakeTransactionRef(mtx);
+
+                TransactionError result = BroadcastTransaction(
+                    *clientModel->node().context(), GetConfig(), tx, err_string,
+                    DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true,
+                    /* wait_callback */ false);
+                if (result == TransactionError::OK) {
+                    Q_EMIT message(tr("Success"),
+                                   tr("Broadcasted transaction successfully."),
+                                   CClientUIInterface::MSG_INFORMATION |
+                                       CClientUIInterface::MODAL);
+                } else {
+                    Q_EMIT message(tr("Error"),
+                                   QString::fromStdString(err_string),
+                                   CClientUIInterface::MSG_ERROR);
+                }
+            } else {
+                // Serialize the PSBT
+                CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+                ssTx << psbtx;
+                GUIUtil::setClipboard(EncodeBase64(ssTx.str()).c_str());
+                Q_EMIT message(tr("PSBT copied"), "Copied to clipboard",
+                               CClientUIInterface::MSG_INFORMATION);
+                return;
+            }
+        }
+        case QMessageBox::Cancel:
+            break;
+        default:
+            assert(false);
+    }
+}
+
 bool WalletView::handlePaymentRequest(const SendCoinsRecipient &recipient) {
     return sendCoinsPage->handlePaymentRequest(recipient);
 }