diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 3b200e21723235006e145f138959a1e94f9b9c54..4870d0f4a29bca0c9419b1354c1b71e499951821 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1399,6 +1399,7 @@ static char *remove_uri_parameters(char *uri);
 static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req);
 static int get_also_info(struct sip_pvt *p, struct sip_request *oreq);
 static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
+static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req);
 static int set_address_from_contact(struct sip_pvt *pvt);
 static void check_via(struct sip_pvt *p, const struct sip_request *req);
 static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
@@ -16121,6 +16122,49 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req)
 	return TRUE;
 }
 
+/*!
+ * \brief Parses SIP reason header according to RFC3326 and sets channel's hangupcause if configured so
+ *  and header present
+ *
+ * \note This is used in BYE and CANCEL request and SIP response, but according to RFC3326 it could
+ *       appear in any request, but makes not a lot of sense in others than BYE or CANCEL.
+ *       Currently only implemented for Q.850 status codes.
+ * \retval 0 success
+ * \retval -1 on failure or if not configured
+ */
+static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req)
+{
+	int ret, cause;
+	const char *rp, *rh;
+
+	if (!pvt->owner) {
+		return -1;
+	}
+
+	if (!ast_test_flag(&pvt->flags[1], SIP_PAGE2_Q850_REASON) ||
+		!(rh = sip_get_header(req, "Reason"))) {
+		return -1;
+	}
+
+	rh = ast_skip_blanks(rh);
+	if (strncasecmp(rh, "Q.850", 5)) {
+		return -1;
+	}
+
+	ret = -1;
+	cause = ast_channel_hangupcause(pvt->owner);
+	rp = strstr(rh, "cause=");
+	if (rp && sscanf(rp + 6, "%3d", &cause) == 1) {
+		ret = 0;
+		ast_channel_hangupcause_set(pvt->owner, cause & 0x7f);
+		if (req->debug) {
+			ast_verbose("Using Reason header for cause code: %d\n",
+						ast_channel_hangupcause(pvt->owner));
+		}
+	}
+	return ret;
+}
+
 /*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled
  *
  * \note This calls parse_uri which has the unexpected property that passing more
@@ -24107,27 +24151,13 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 		msg = "";
 
 	sipmethod = find_sip_method(msg);
-
 	owner = p->owner;
 	if (owner) {
-		const char *rp = NULL, *rh = NULL;
-
 		ast_channel_hangupcause_set(owner, 0);
-		if (ast_test_flag(&p->flags[1], SIP_PAGE2_Q850_REASON) && (rh = sip_get_header(req, "Reason"))) {
-			rh = ast_skip_blanks(rh);
-			if (!strncasecmp(rh, "Q.850", 5)) {
-				int cause = ast_channel_hangupcause(owner);
-				rp = strstr(rh, "cause=");
-				if (rp && sscanf(rp + 6, "%30d", &cause) == 1) {
-					ast_channel_hangupcause_set(owner, cause & 0x7f);
-					if (req->debug)
-						ast_verbose("Using Reason header for cause code: %d\n", ast_channel_hangupcause(owner));
-				}
-			}
-		}
-
-		if (!ast_channel_hangupcause(owner))
+		if (use_reason_header(p, req)) {
+			/* Use the SIP cause */
 			ast_channel_hangupcause_set(owner, hangup_sip2cause(resp));
+		}
 	}
 
 	if (p->socket.type == AST_TRANSPORT_UDP) {
@@ -26419,6 +26449,8 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req)
 		return 0;
 	}
 
+	use_reason_header(p, req);
+
 	/* At this point, we could have cancelled the invite at the same time
 	   as the other side sends a CANCEL. Our final reply with error code
 	   might not have been received by the other side before the CANCEL
@@ -26435,7 +26467,7 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req)
 
 	stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
 	if (p->owner) {
-		sip_queue_hangup_cause(p, 0);
+		sip_queue_hangup_cause(p, ast_channel_hangupcause(p->owner));
 	} else {
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 	}
@@ -26614,6 +26646,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
 		stop_session_timer(p); /* Stop Session-Timer */
 	}
 
+	use_reason_header(p, req);
 	if (!ast_strlen_zero(sip_get_header(req, "Also"))) {
 		ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method.  Ask vendor to support REFER instead\n",
 			ast_sockaddr_stringify(&p->recv));
@@ -26654,7 +26687,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
 				ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR);
 		}
 	} else if (p->owner) {
-		sip_queue_hangup_cause(p, 0);
+		sip_queue_hangup_cause(p, ast_channel_hangupcause(p->owner));
 		sip_scheddestroy_final(p, DEFAULT_TRANS_TIMEOUT);
 		ast_debug(3, "Received bye, issuing owner hangup\n");
 	} else {