yticksが大きい場合、他の回答のメソッドは正しく機能しません。ylabelは目盛りと重複するか、Figureの左側でクリップされるか、完全に非表示/外部でクリップされます。
Hagneの回答を変更して、xlabelとylabelの両方で1列を超えるサブプロットで機能し、図でylabelが見えるようにプロットをシフトします。
def set_shared_ylabel(a, xlabel, ylabel, labelpad = 0.01, figleftpad=0.05):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""
    f = a[0,0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below
    # get the center position for all plots
    top = a[0,0].get_position().y1
    bottom = a[-1,-1].get_position().y0
    # get the coordinates of the left side of the tick labels
    x0 = 1
    x1 = 1
    for at_row in a:
        at = at_row[0]
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
            x1 = bboxes.x1
    tick_label_left = x0
    # shrink plot on left to prevent ylabel clipping
    # (x1 - tick_label_left) is the x coordinate of right end of tick label,
    # basically how much padding is needed to fit tick labels in the figure
    # figleftpad is additional padding to fit the ylabel
    plt.subplots_adjust(left=(x1 - tick_label_left) + figleftpad)
    # set position of label, 
    # note that (figleftpad-labelpad) refers to the middle of the ylabel
    a[-1,-1].set_ylabel(ylabel)
    a[-1,-1].yaxis.set_label_coords(figleftpad-labelpad,(bottom + top)/2, transform=f.transFigure)
    # set xlabel
    y0 = 1
    for at in axes[-1]:
        at.set_xlabel('')  # just to make sure we don't and up with multiple labels
        bboxes, _ = at.xaxis.get_ticklabel_extents(fig.canvas.renderer)
        bboxes = bboxes.inverse_transformed(fig.transFigure)
        yt = bboxes.y0
        if yt < y0:
            y0 = yt
    tick_label_bottom = y0
    axes[-1, -1].set_xlabel(xlabel)
    axes[-1, -1].xaxis.set_label_coords((left + right) / 2, tick_label_bottom - labelpad, transform=fig.transFigure)
これは次の例で機能しますが、Hagneの答えはylabelを描画せず(キャンバスの外側にあるため)、KYCのylabelは目盛りラベルと重複しています。
import matplotlib.pyplot as plt
import itertools
fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
set_shared_ylabel(axes, 'common X', 'common Y')
plt.show()
または、無色の軸で問題がなければ、ジュリアンチェンのソリューションを変更して、ylabelが目盛りラベルと重複しないようにしました。 
基本的に、無色のylimを設定して、サブプロットの最大のylimと一致させるだけで、無色の目盛りラベルがylabelの正しい位置を設定する必要があります。
ここでも、クリッピングを防ぐためにプロットを縮小する必要があります。ここでは縮小する量をハードコードしましたが、試してみて、うまくいく数値を見つけたり、上記の方法のように計算したりできます。
import matplotlib.pyplot as plt
import itertools
fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
miny = maxy = 0
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
    miny = min(miny, a.get_ylim()[0])
    maxy = max(maxy, a.get_ylim()[1])
# add a big axes, hide frame
# set ylim to match the largest range of any subplot
ax_invis = fig.add_subplot(111, frameon=False)
ax_invis.set_ylim([miny, maxy])
# hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")
# shrink plot to prevent clipping
plt.subplots_adjust(left=0.15)
plt.show()