diff --git a/ghost/members-api/index.js b/ghost/members-api/index.js
index d3c83dbeec..9b32765905 100644
--- a/ghost/members-api/index.js
+++ b/ghost/members-api/index.js
@@ -154,6 +154,12 @@ module.exports = function MembersApi({
             return res.end('Bad Request.');
         }
 
+        // NOTE: never allow "Complimenatry" plan to be subscribed to from the client
+        if (plan.toLowerCase() === 'complimentary') {
+            res.writeHead(400);
+            return res.end('Bad Request.');
+        }
+
         let email;
         try {
             if (!identity) {
@@ -276,6 +282,11 @@ module.exports = function MembersApi({
             return res.end('No permission');
         }
 
+        if (subscription.plan.nickname === 'Complimentary') {
+            res.writeHead(400);
+            return res.end('Bad request');
+        }
+
         if (cancelAtPeriodEnd === undefined) {
             throw new common.errors.BadRequestError({
                 message: 'Canceling membership failed!',
diff --git a/ghost/members-api/lib/stripe/index.js b/ghost/members-api/lib/stripe/index.js
index 6dc1ccb638..66827a25f2 100644
--- a/ghost/members-api/lib/stripe/index.js
+++ b/ghost/members-api/lib/stripe/index.js
@@ -128,9 +128,10 @@ module.exports = class StripePaymentProcessor {
             return subscription.status !== 'canceled';
         });
 
-        await Promise.all(activeSubscriptions.map((subscription) => {
-            return del(this._stripe, 'subscriptions', subscription.id);
-        }));
+        for (const subscription of activeSubscriptions) {
+            const updatedSubscription = await del(this._stripe, 'subscriptions', subscription.id);
+            await this._updateSubscription(updatedSubscription);
+        }
 
         return true;
     }
@@ -177,6 +178,40 @@ module.exports = class StripePaymentProcessor {
         });
     }
 
+    async setComplimentarySubscription(member) {
+        const subscriptions = await this.getActiveSubscriptions(member);
+        const complimentaryPlan = this._plans.find(plan => (plan.nickname === 'Complimentary'));
+
+        const customer = await this._customerForMemberCheckoutSession(member);
+
+        if (!subscriptions.length) {
+            const subscription = await create(this._stripe, 'subscriptions', {
+                customer: customer.id,
+                items: [{
+                    plan: complimentaryPlan.id
+                }]
+            });
+
+            await this._updateSubscription(subscription);
+        } else {
+            // NOTE: we should only ever have 1 active subscription, but just in case there is more update is done on all of them
+            for (const subscription of subscriptions) {
+                const updatedSubscription = await update(this._stripe, 'subscriptions', subscription.id, {
+                    proration_behavior: 'none',
+                    plan: complimentaryPlan.id
+                });
+
+                await this._updateSubscription(updatedSubscription);
+            }
+        }
+    }
+
+    async cancelComplimentarySubscription(member) {
+        // NOTE: a more explicit way would be cancelling just the "Complimentary" subscription, but doing it
+        //       through existing method achieves the same as there should be only one subscription at a time
+        await this.cancelAllSubscriptions(member);
+    }
+
     async getActiveSubscriptions(member) {
         const subscriptions = await this.getSubscriptions(member);
 
diff --git a/ghost/members-api/lib/users.js b/ghost/members-api/lib/users.js
index 5febeeba4a..e7f1e8cc73 100644
--- a/ghost/members-api/lib/users.js
+++ b/ghost/members-api/lib/users.js
@@ -75,6 +75,18 @@ module.exports = function ({
         }
     }
 
+    async function setComplimentarySubscription(member) {
+        if (stripe) {
+            await stripe.setComplimentarySubscription(member);
+        }
+    }
+
+    async function cancelComplimentarySubscription(member) {
+        if (stripe) {
+            await stripe.cancelComplimentarySubscription(member);
+        }
+    }
+
     async function get(data, options) {
         debug(`get id:${data.id} email:${data.email}`);
         const member = await getMember(data, options);
@@ -146,6 +158,8 @@ module.exports = function ({
         get,
         destroy,
         getStripeSubscriptions,
+        setComplimentarySubscription,
+        cancelComplimentarySubscription,
         destroyStripeSubscriptions
     };
 };