pagination redirecting from page number url before page requested

You should never use query_post as it breaks the main query object and resets it to the current custom query. This breaks plugins and custom functionalities like related posts and pagination. I have done an extensive answer on that, so be sure to check it out, as well as the answer by @Rarst.

It should also be noted, single pages, just as static front pages uses page and not paged as normal archive pages and pages do

Lets first look at your related posts function:

RELATED POSTS

We would first want to properly code the function to allow for it to be safe and dynamic. I accept that $id should be the single post ID of the post you are viewing, so with that in mind, lets code the function:

Just a few notes before we do:

  • The code is commented, so it will be easy to follow

  • The code requires PHP 5.4 +

  • Modify the code as needed

Here is the code

/**
 * Function to return realted posts_per_page
 *
 * @param (array) $args Compatible argumnets to pass to WP_Query
 * @return $author_articles
 */
function get_author_articles( $args = [] )
{
    // First make sure we are on a single page, else return false
    if ( !is_single() )
        return false;

    // Get the single post object we are on
    $current_post = get_queried_object();

    // Set our $page variable
    $page = get_query_var( 'page' ) ? get_query_var( 'page' ) : 0;

    // backwards finds CPT 'blogs' this staff member is related to.
    $meta_query_defaults = [
        'post__not_in'   => $current_post->ID, // Excludes the current post
        'paged'          => $page,
        'post_type'      => $current_post->post_type,
        'posts_per_page' => 20,
        'meta_query'     => [
            [
                'key'     => 'blog_author', // name of custom field, ACF
                'value'   => $current_post->ID,  // CPT 'staff' id.
                'compare' => 'LIKE'
            ]
        ],
    ];

    // Add our custom arguments to the $meta_query_defaults array
    if (    $args
         && is_array( $args )
    ) {
        $meta_query_defaults = wp_parse_args(  $args, $meta_query_defaults );
    }

    $author_articles = new WP_Query( $meta_query_defaults );

    return $author_articles;
}

You can pass, as first parameter, an array of parameters that is valid for WP_Query to adjust and modify the default parameters in the function which is passed to WP_Query

PAGINATION

As I have stated, single post pages and static front pages uses page and not paged. In order to make pagination work, you would require a complete custom function. I have done such a function a while ago, which you can check here.

Here is slightly modified versions

function get_single_pagination_link( $pagenum = 1 ) {
    global $wp_rewrite;

    if(    !is_single() 
        || !$wp_rewrite->permalink_structure 
    )
        return false;

    $pagenum = (int) $pagenum;

    $post_id = get_queried_object_id();
    $request = get_permalink( $post_id );

    if ( $pagenum > 1 )
        $request = trailingslashit( $request ) . user_trailingslashit( $pagenum );
   return esc_url( $request );
}

function get_next_single_page_link ( $label = null, $max_page = 0 ) {
    global $wp_query;

    if( !is_single() ) 
        return false;

    if ( !$max_page ) {
        $max_page = $wp_query->max_num_pages;
    }

    $paged = ( get_query_var('page') ) ? get_query_var('page') : 1;

    $next_page = intval($paged) + 1;

    if ( null === $label ) {
        $label = __( 'Next Page »' );
    }

    if ( ( $next_page <= $max_page ) ) {
        return '<a href="' . get_single_pagination_link( $next_page ) . '">' . $label . '</a>';
    } else {
        return false;
    }
}

function get_previous_single_page_link( $label = null ) {

    if( !is_single() ) 
        return false; 

    $paged = ( get_query_var('page') ) ? get_query_var('page') : 1;

    $prev_page = intval($paged) - 1;

    if ( null === $label ) {
        $label = __( '&laquo; Previous Page' );
    }

    if ( ( $prev_page > 0 ) ) {
        return '<a href="' . get_single_pagination_link( $prev_page ) . '">' . $label . '</a>';
    } else {
        return false;
    }
}

BASIC USAGE

You can now use it as follow

$q = get_author_articles();
if ( $q->have_posts() ) {
    while ( $q->have_posts() ) {
    $q->the_post();

        // Add your markup, etc.

    }
    echo get_previous_single_page_link();
    echo get_next_single_page_link( null , $q->max_num_pages );

    wp_reset_postdata();
}