I am working with the following architecture:
- OpenGL ES 2 on iOS
 - Two EAGL contexts with the same ShareGroup
 - Two threads (server, client = main thread); the server renders stuff to textures, the client displays the textures using simple textured quads.
 
Additional detail to the server thread (working code)
An fbo is created during initialization:
void init(void) {
    glGenFramebuffer(1, &fbo);
}
The render loop of the server looks roughly like this:
GLuint loop(void) {
    glBindFrameBuffer(GL_FRAMEBUFFER, fbo);
    glViewport(0,0,width,height);
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
    // Framebuffer completeness check omitted
    glClear(GL_COLOR_BUFFER_BIT);
    // actual drawing code omitted
    // the drawing code bound other textures, so..
    glBindTexture(GL_TEXTURE_2D, tex);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, GL_NONE);
    glFlush();
    return tex;
}
All this works fine so far.
New (buggy) code
Now i want to add Multisampling to the server thread, using the GL_APPLE_framebuffer_multisample extension and modified the the initialization code like this:
void init(void) {
    glGenFramebuffer(1, &resolve_fbo);
    glGenFramebuffers(1, &sample_fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, sample_fbo);
    glGenRenderbuffers(1, &sample_colorRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, sample_colorRenderbuffer);
    glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sample_colorRenderbuffer);
    // Framebuffer completeness check (sample_fbo) omitted
    glBindRenderbuffer(GL_RENDERBUFFER, GL_NONE);
    glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
}
The main loop has been changed to:
GLuint loop(void) {
    glBindFrameBuffer(GL_FRAMEBUFFER, sample_fbo);
    glViewport(0,0,width,height);
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glClear(GL_COLOR_BUFFER_BIT);
    // actual drawing code omitted
    glBindFramebuffer(GL_FRAMEBUFFER, resolve_fbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
    // Framebuffer completeness check (resolve_fbo) omitted
    // resolve multisampling
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, resolve_fbo);
    glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, sample_fbo);
    glResolveMultisampleFramebufferAPPLE();
    // the drawing code bound other textures, so..
    glBindTexture(GL_TEXTURE_2D, tex);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, GL_NONE);
    glFlush();
    return tex;
}
What i see now is that a texture contains data from multiple loop() calls, blended together. I guess I'm either missing an 'unbind' of some sort, or probably a glFinish() call (I previously had such a problem at a different point, I set texture data with glTexImage2D() and used it right afterwards - that required a glFinish() call to force the texture to be updated).
However inserting a glFinish() after the drawing code didn't change anything here..
                        
Oh nevermind, such a stupid mistake. I omitted the detail that the loop() method actually contains a for loop and renders multiple textures, the mistake was that i bound the sample fbo only before this loop, so after the first run the resolve fbo was bound..
Moving the fbo binding inside the loop fixed the problem.
Anyway, thanks @ all the readers and sorry for wasting your time :)